diff --git a/index.js b/index.js index e7396cd61..df6079be2 100644 --- a/index.js +++ b/index.js @@ -1216,6 +1216,12 @@ INDEX=[ "func":1 }, { +"ref":"tf.advanced.app.App.featureTypes", +"url":16, +"doc":"For which node types is each feature defined? It computes on the fly for each feature the node types for which the feature has defined values. Parameters show: boolean, optional True Whether to output the result in pretty markdown. Returns - dict If show is true, None is returned, but if show is false, a dict is returned, keyed by features and the value for each feature is the list of types for which it has defined values.", +"func":1 +}, +{ "ref":"tf.advanced.app.App.context", "url":16, "doc":"Result of interpreting all configuration options in config.yaml ." @@ -2009,7 +2015,7 @@ INDEX=[ { "ref":"tf.core.files.annotateDir", "url":33, -"doc":"Return the input and output and report directories for a specific annotation tool. The input directory is located next to the TF data of the corpus The output directory is located in the _temp directory next to the TF data of the corpus The report directory is located in the report directory next to the TF data of the corpus Parameters app: object the TF app tool: string The name of the annotation tool Returns - string The path of the working directory for that tool and that corpus", +"doc":"Return the input and output and report directories for a specific annotation tool. The input directory is located next to the TF data of the corpus The output directory is located in the _temp directory next to the TF data of the corpus of the corpus Parameters app: object the TF app tool: string The name of the annotation tool Returns - string The path of the working directory for that tool and that corpus", "func":1 }, { @@ -3592,7 +3598,7 @@ INDEX=[ { "ref":"tf.about.releases", "url":72, -"doc":" Release notes ! hint \"Consult the tutorials after changes\" When we change the API, we make sure that the tutorials show off all possibilities. See the app-specific tutorials via tf.about.corpora . - The TEI converter is still in active development. If you need the latest version, clone the TF repo and in its top-level directory run the command: sh pip install -e . 12 12.5 12.5.1 2024-06-06 WATM production tweaks: By default, WATM files are written to versioned directories inside the _temp directory. Existing data may be overwritten. However, if you pass a flag indicating that it is for production, the result is written to a new versioned directory inside watm . The new versioned directories created in this way have a suffix -001 , -002 , etc. This helps to keep published WATM fixed. NER more refined entity lookup When looking up entities on the basis of spreadsheet instructions, you can now give spreadsheets for the whole corpus, and for sections and subsections and ranges of them. The more specificly targeted spreadsheets override the more generally targeted ones. The lookup is also more efficient, and it prefers longer matches over shorter ones. After the lookup, a detailed tsv file is generated with details information about the hits: to which triggers in which spreadsheet they correspond, and how many are found in which paragraphs. 12.5.0 2024-05-28 Fixes in NER Browser: If you click a chunk heading you get a box with the whole section, scrollable, just above the section. Previously, you got this at the end of the chunk, which could be confusing if the chunk is long and the context box disappears below the bottom of the page. When looking for complex names and translating such names into tokens, leave out tokens that are just spaces. The NER browser will repeatedly read the list of annotation sets. This is needed when sets have been added or deleted from outside the NER browser. You do not have to restart the NER browser in that case. Hyphenated occurrences were not found. That has been fixed, without decreasing the speed of the algorithm too much. Once a set of entities has been marked, it can now also be baked into the TF dataset. Fix in display algorithm In plain display, when a line break occurs, we needed a trick to make it happen, because such a display is a flex box. A simple has no effect. We found the trick and it worked. However, if the break occurs in something that is also highlighted, the trick did not work anymore, because the highlight introduces an extra level. We fixed it by disrupting the extra span level for the tricked br and resuming it after the br. 12.4 12.4.5,6 2024-05-13 Fix in the autodownload by TF. When TF downloads the complete.zip of a corpus and extracts it, it does not remove previously exisiting files in the directories in which the data files land. That pre-existing material can interfere in surprising ways with the resulting dataset, as Christian H\u00f8jgaard experienced (thanks Christian for reporting it and taking the time to help me pinpoint the culprit). The fix is that TF first inspects the complete.zip and determines what the folders are in which the file __checkout__.txt exists. These are the folders that do not tolerate pre-existing material. The will be deleted before extracting the zip file. Fix in displaying nodes by means of pretty() . Sometimes an error is raised when composing the features and values that should be displayed for a node (spotted by Cody Kingham, thanks). It happens in cases where you want to show a feature of a related node on a node, but the related node does not exist. In that case TF tries to access an undefined variable. That has been fixed. Now these cases will not raise errors, but you might still be surprised by the fact that in some cases the related node does not exist. 12.4.3,4 2024-05-08 Fix in TF browser, spotted by Jorik Groen. When exporting query results, the values features used in the query were not written to the table at all. The expected behaviour was that features used in the query lead to extra columns in the exported table. It has been fixed. The cause was an earlier fix in the display of features in query results. This new fix only affects the export function from the browser, not the tf.advanced.display.export function, which did not have this bug. The pipeline from TEI or PageXML via TF to WATM is a complex thing to steer. There is now a new class tf.convert.makewatm that takes care of this: it provides a command line interface to perform the necessary convert steps. Moreover, you can use it as a base class and extend it with additional convert steps and options, with minimal code. 12.4.2 2024-04-24 Tiny fixes in the TEI and WATM conversions. 12.4.1 2024-04-24 Improvements in the TEI and WATM conversions. 12.4.0 2024-04-21 Support for [Marimo notebooks](https: docs.marimo.io/index.html). TF detects when its run in a notebook, and also in what kind of notebook: ipython (~ Jupyter) or marimo . When it needs to display material in the output of a cell, it will choose the methods that are suitable for the kind of notebook it is working in. 12.3 12.3.7 2024-04-19 Improvements in tf.convert.watm : the resulting data is much more compact, because: you can choose to export it as TSV instead of JSON; no annotations of type node are produced anymore, they only served to map annotations and text segments to TF nodes; now that mapping is exported as a simple TSV file; you can opt to exclude an arbitrary set of tags from being exported as WATM annotations. 12.3.6 2024-04-16 Minimal fixes in tf.convert.tei : it can handle a biography. Fixed prettyTuple() when passed _asString=True : it did not pass this on to pretty() which caused a Python error. 12.3.5 2024-03-26 extra functionality: When adding types with tf.dataset.modify you can link nodes of a newly added type to nodes that were added as the preiviously added type. This is a bit of a limited and ad hoc extension of the functionality of this function. I needed a quick fix to add nodes for entities and entity occurrences at the same time and link them with edges. This is for the corpus [ CLARIAH/wp6-missieven ](https: github.com/CLARIAH/wp6-missieven). fix: the express download of a dataset (complete.zip) was nit triggered in all cases where it should. 12.3.4 2024-02-26 The output of tf.convert.watm has been changed. It now generates token files per section, where you can configure the TF section level for that. The syntax for targets has been changed: more things are possible. Tests have been adapted and strengthened. 12.3.3 2024-02-20 Fix in tf.advanced.repo.publishRelease : it did not work if you are on a branch named main because master was hard-coded in the source code. Now it takes the branch name from the app context. Do not forget to specify branch: main under the provenanceSpecs in your /app/config.yaml . Many thanks to Tony Jorg for reporting this error. 12.3.1,2 2024-02-15 Minor improvements to the WATM converter, and an update of its docs. 12.3.0 2024-02-08 A new data export conversion, from TF to WATM. See tf.convert.watm . WATM is a not yet hardened data format that powers the publishing line for text and annotations built by Team Text at [KNAW/HuC Digital Infrastructure](https: di.huc.knaw.nl/text-analysis-en.html). Currently this export is used for the corpora [Mondriaan Proeftuin](https: github.com/annotation/mondriaan) [Suriano Letters](https: gitlab.huc.knaw.nl/suriano/letters) [TransLatin Corpus](https: gitlab.huc.knaw.nl/translatin/corpus) Small fixes in tf.convert.addnlp : when the NLP data is integrated in the TF dataset, the NLP-generated features will get some metadata 12.2 12.2.8,9,10 2024-01-24/25 TF can auto-download extra data with a TF dataset, e.g. a directory with named entities ( ner ) as in the [suriano corpus](https: gitlab.huc.knaw.nl/suriano/letters). However, this only worked when the repo was in the github backend and the extra data had been packed for express-download and attached to a release. Now it also works with the normal download methods using the GitHub and GitLab APIs. So, after the move of Suriano from GitHub to GitLab, this functionality is still available. There was a glitch in the layout of the NER tool which caused section labels to be chopped off at the margin, only in notebooks. Thats has been fixed by moving some CSS code from one file to an other. 12.2.7 2024-01-23 There were issues with starting up the Text-Fabric browser: If the system could not start the browser, the TF stopped the webserver. That is not helpful, because one can always open a browser and enter the url in the address bar. Now TF shows the url rather prominently when it does not open a browser. If debug mode is on, Flask reloads the whole process, and that might include opening the browser as well. Now Flask only opens the browser after the startup of the webserver, and not anymore after successive reloads. 12.2.6 2024-01-15 Somehow the express way of downloading data (via complete.zip attached to the latest release) did not get triggered in all cases where it should. It is now triggered in more cases than before. 12.2.5 2023-12-18 Small fix in NER browser: prevent submitting the form if the focus is in a textarea field or in an input field that does not have type=submit. 12.2.3,4 2023-12-09 Writing support for Ugaritic, thanks to Martijn Naaijer and Christian H\u00f8jgaard for converting a Ugaritic corpus to TF. Fix in display functions (continued): The logic of feature display, fixed in the previous version, was not effective when things are displayed in the TF browser. Because in the TF browser the features of the last query were passed as extraFeatures instead of tupleFeatures . This has been fixed by using tupleFeatures in the TF browser as well. 12.2.2 2023-12-02 Fix in display functions, thanks to Tony Jurg: if you do A.pretty(x, queryFeatures=False, extraFeatures=\"yy zz\") the extra features were not shown. So there was no obvious way to control exactly the features that you want to show in a display. That has been fixed. Further clarification: the node features that are used by a query are stored in the display option tupleFeatures . That is what causes them to be displayed in subsequent display statements. You can also explicitly set/pass the tupleFeatures parameter. However, the fact that queryFeatures=False prohibited the display of features mentioned in extraFeatures was against the intuitions. Improvements in the PageXML conversion. There are token features str , after that reflect the logical tokens There are token features rstr , rafter that reflect the physical tokens The distincition between logical and physical is that physical token triplets with the soft hyphen as the middle one, are joined to one logical token; this happens across line boundaries, but also region and page boundaries. 12.2.0,1 2023-11-28 New conversion tool: from PageXML. Still in its infancy. It uses the [PageXML tools](https: github.com/knaw-huc/pagexml) by Marijn Koolen. For an example see [translatin/logic](https: gitlab.huc.knaw.nl/translatin/logic/-/blob/main/tools/convertPlain.ipynb?ref_type=heads). Fix: TF did not fetch an earlier version of a corpus if the newest release contains a complete.zip (which only has the latest version). For some technical reason that still escapes me, the TF browser was slow to start. Fixed it by saying threaded=True to Flask, as suggested on [stackoverflow](https: stackoverflow.com/a/11150849/15236220) From now on: TF does not try to download complete.zip if you pass a version argument to the use() command. 12.1 12.1.6,7 2023-11-15 Various fixes: Some package data was not included for the NER annotation tool. In the NER tool, the highlighting of hits of the search pattern is now exact, it was sometimes off. Deleted tf.tools.docsright again, but developed it further in [docsright](https: github.com/annotation/docsright). 12.1.5 2023-11-02 Improvement in dependencies. Text-Fabric is no longer mandatory dependent on openpyxl , pandas , pyarrow , lxml . The optional dependencies on pygithub and python-gitlab remain, but most users will never need them, because TF can also fetch the complete.zip that is available as release asset for most corpora. Whenever TF invokes a module that is not in the mandatory dependencies, it will act gracefully, providing hints to install the modules in question. 12.1.3,4 2023-11-01 API change in the Annotator: Calling the annotator is now easier: A.makeNer() (No need to make an additional import statement.) This will give you access to all annotation methods, including using a spreadsheet to read annotation instructions from. Removal of deprecated commands (on the command line) in version 11: text-fabric (has become tf ) text-fabric-zip (has become tf-zip ) text-fabric-make (has become tf-make ) Bug fixes: [ 81](https: github.com/annotation/text-fabric/issues/81) and [ 82](https: github.com/annotation/text-fabric/issues/82) Spell-checked all bits of the TF docs here (33,000 lines). Wrote a script tf.tools.docsright to separate the code content from the markdown content, and to strip bits from the markdown content that lead to false positives for the spell checker. Then had the Vim spell checker run over those lines and corrected all mistakes by hand. Still, there might be grammar errors and content inaccuracies. 12.1.4 follows 12.1.3. quickly, because in corpora without a NER configuration file, TF did not start up properly. 12.1.1,2 2023-10-29 Bug fix: the mechanism to make individual exceptions when adding named entities in the tf.browser.ner.annotate tool was broken. Thanks to Daniel Swanson for spotting it. Additional fixes and enhancements. 12.1.0 2023-10-28 New stuff In the TF browser there will be a new tab in the vertical sidebar: Annotate , which will give access to manual annotation tools. I am developing the first one, a tool to annotate named entities efficiently, both in the TF browser and in a Jupyter Notebook. Reed more in tf.about.annotate . These tools will let you save your work as files on your own computer. In tf.convert.addnlp we can now extract more NLP information besides tokens and sentences: part-of-speech, morphological tagging, lemmatisation, named entity recognition Fixes in the TEI converter. 12.0 12.0.6,7 2023-09-13 Trivial fix in code that exports the data from a job in the TF browser. In the meanwhile there is unfinished business in the Annotate tab in the TF browser, that will come into production in the upcoming 12.1 release. The Chrome browser has an attractive feature that other browsers such as Safari lack: It supports the CSS property [content-visibility](https: developer.mozilla.org/en-US/docs/Web/CSS/content-visibility). With this property you can prevent the browser to do the expensive rendering of content that is not visible on the screen. That makes it possible to load a lot of content in a single page without tripping up the browser. You also need the [ IntersectionObserver API](https: developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API), but that is generally supported by browsers. With the help of that API you can restrict the binding of event listeners to elements that are visible on the screen. So, you can open the TF browser in Chrome by passing the option chrome . But if Chrome is not installed, it will open in the default browser anyway. Also, when the opening of the browser fails somehow, the web server is stopped. 12.0.5 2023-07-10 Fixed references to static files that still went to /server instead of /browser . This has to do with the new approach to the TF browser. 12.0.0-4 2023-07-05 Simplification The TF browser no longer works with a separate process that holds the TF corpus data. Instead, the web server (flask) loads the corpus itself. This will restrict the usage of the TF browser to local-single-user scenarios. TF no longer exposes the installation options [browser, pandas] pip install 'text-fabric[browser]' pip install 'text-fabric[pandas]' If you work with Pandas (like exporting to Pandas) you have to install it yourself: pip install pandas pyarrow The TF browser is always supported. The reason to have these distinct capabilities was that there are python libraries involved that do not install on the iPad. The simplification of the TF browser makes it possible to be no longer dependent on these modules. Hence, TF can be installed on the iPad, although the TF browser works is not working there yet. But the auto-downloading of data from GitHub / GitLab works. Minor things Header. After loading a dataset, a header is shown with shows all kinds of information about the corpus. But so far, it did not show the TF app settings. Now they are included in the header. There are two kinds: the explicitly given settings and the derived and computed settings. The latter ones will be suppressed when loading a dataset in a Jupyter notebook, because these settings can become quite big. You can still get them with A.showContext() . In the TF browser they will be always included, you find it in the Corpus tab. - Older releases See tf.about.releasesold ." +"doc":" Release notes ! hint \"Consult the tutorials after changes\" When we change the API, we make sure that the tutorials show off all possibilities. See the app-specific tutorials via tf.about.corpora . - The TEI converter is still in active development. If you need the latest version, clone the TF repo and in its top-level directory run the command: sh pip install -e . 12 12.5 12.5.2 2024-06-13 New function to show the types for which each feature has defined values. Thanks to Marek Pol\u00e1\u0161ek for asking for it, writing an algorithm to produce this information, and then speeding it up 10-fold! For details see this [cookbook](https: nbviewer.org/github/ETCBC/bhsa/blob/master/tutorial/cookbook/lexemes.ipynb) Working on integrating NER by spreadsheet in the TF browser. This is currently in an unfinished state. 12.5.1 2024-06-06 WATM production tweaks: By default, WATM files are written to versioned directories inside the _temp directory. Existing data may be overwritten. However, if you pass a flag indicating that it is for production, the result is written to a new versioned directory inside watm . The new versioned directories created in this way have a suffix -001 , -002 , etc. This helps to keep published WATM fixed. NER more refined entity lookup When looking up entities on the basis of spreadsheet instructions, you can now give spreadsheets for the whole corpus, and for sections and subsections and ranges of them. The more specificly targeted spreadsheets override the more generally targeted ones. The lookup is also more efficient, and it prefers longer matches over shorter ones. After the lookup, a detailed tsv file is generated with details information about the hits: to which triggers in which spreadsheet they correspond, and how many are found in which paragraphs. 12.5.0 2024-05-28 Fixes in NER Browser: If you click a chunk heading you get a box with the whole section, scrollable, just above the section. Previously, you got this at the end of the chunk, which could be confusing if the chunk is long and the context box disappears below the bottom of the page. When looking for complex names and translating such names into tokens, leave out tokens that are just spaces. The NER browser will repeatedly read the list of annotation sets. This is needed when sets have been added or deleted from outside the NER browser. You do not have to restart the NER browser in that case. Hyphenated occurrences were not found. That has been fixed, without decreasing the speed of the algorithm too much. Once a set of entities has been marked, it can now also be baked into the TF dataset. Fix in display algorithm In plain display, when a line break occurs, we needed a trick to make it happen, because such a display is a flex box. A simple has no effect. We found the trick and it worked. However, if the break occurs in something that is also highlighted, the trick did not work anymore, because the highlight introduces an extra level. We fixed it by disrupting the extra span level for the tricked br and resuming it after the br. 12.4 12.4.5,6 2024-05-13 Fix in the autodownload by TF. When TF downloads the complete.zip of a corpus and extracts it, it does not remove previously exisiting files in the directories in which the data files land. That pre-existing material can interfere in surprising ways with the resulting dataset, as Christian H\u00f8jgaard experienced (thanks Christian for reporting it and taking the time to help me pinpoint the culprit). The fix is that TF first inspects the complete.zip and determines what the folders are in which the file __checkout__.txt exists. These are the folders that do not tolerate pre-existing material. The will be deleted before extracting the zip file. Fix in displaying nodes by means of pretty() . Sometimes an error is raised when composing the features and values that should be displayed for a node (spotted by Cody Kingham, thanks). It happens in cases where you want to show a feature of a related node on a node, but the related node does not exist. In that case TF tries to access an undefined variable. That has been fixed. Now these cases will not raise errors, but you might still be surprised by the fact that in some cases the related node does not exist. 12.4.3,4 2024-05-08 Fix in TF browser, spotted by Jorik Groen. When exporting query results, the values features used in the query were not written to the table at all. The expected behaviour was that features used in the query lead to extra columns in the exported table. It has been fixed. The cause was an earlier fix in the display of features in query results. This new fix only affects the export function from the browser, not the tf.advanced.display.export function, which did not have this bug. The pipeline from TEI or PageXML via TF to WATM is a complex thing to steer. There is now a new class tf.convert.makewatm that takes care of this: it provides a command line interface to perform the necessary convert steps. Moreover, you can use it as a base class and extend it with additional convert steps and options, with minimal code. 12.4.2 2024-04-24 Tiny fixes in the TEI and WATM conversions. 12.4.1 2024-04-24 Improvements in the TEI and WATM conversions. 12.4.0 2024-04-21 Support for [Marimo notebooks](https: docs.marimo.io/index.html). TF detects when its run in a notebook, and also in what kind of notebook: ipython (~ Jupyter) or marimo . When it needs to display material in the output of a cell, it will choose the methods that are suitable for the kind of notebook it is working in. 12.3 12.3.7 2024-04-19 Improvements in tf.convert.watm : the resulting data is much more compact, because: you can choose to export it as TSV instead of JSON; no annotations of type node are produced anymore, they only served to map annotations and text segments to TF nodes; now that mapping is exported as a simple TSV file; you can opt to exclude an arbitrary set of tags from being exported as WATM annotations. 12.3.6 2024-04-16 Minimal fixes in tf.convert.tei : it can handle a biography. Fixed prettyTuple() when passed _asString=True : it did not pass this on to pretty() which caused a Python error. 12.3.5 2024-03-26 extra functionality: When adding types with tf.dataset.modify you can link nodes of a newly added type to nodes that were added as the preiviously added type. This is a bit of a limited and ad hoc extension of the functionality of this function. I needed a quick fix to add nodes for entities and entity occurrences at the same time and link them with edges. This is for the corpus [ CLARIAH/wp6-missieven ](https: github.com/CLARIAH/wp6-missieven). fix: the express download of a dataset (complete.zip) was nit triggered in all cases where it should. 12.3.4 2024-02-26 The output of tf.convert.watm has been changed. It now generates token files per section, where you can configure the TF section level for that. The syntax for targets has been changed: more things are possible. Tests have been adapted and strengthened. 12.3.3 2024-02-20 Fix in tf.advanced.repo.publishRelease : it did not work if you are on a branch named main because master was hard-coded in the source code. Now it takes the branch name from the app context. Do not forget to specify branch: main under the provenanceSpecs in your /app/config.yaml . Many thanks to Tony Jorg for reporting this error. 12.3.1,2 2024-02-15 Minor improvements to the WATM converter, and an update of its docs. 12.3.0 2024-02-08 A new data export conversion, from TF to WATM. See tf.convert.watm . WATM is a not yet hardened data format that powers the publishing line for text and annotations built by Team Text at [KNAW/HuC Digital Infrastructure](https: di.huc.knaw.nl/text-analysis-en.html). Currently this export is used for the corpora [Mondriaan Proeftuin](https: github.com/annotation/mondriaan) [Suriano Letters](https: gitlab.huc.knaw.nl/suriano/letters) [TransLatin Corpus](https: gitlab.huc.knaw.nl/translatin/corpus) Small fixes in tf.convert.addnlp : when the NLP data is integrated in the TF dataset, the NLP-generated features will get some metadata 12.2 12.2.8,9,10 2024-01-24/25 TF can auto-download extra data with a TF dataset, e.g. a directory with named entities ( ner ) as in the [suriano corpus](https: gitlab.huc.knaw.nl/suriano/letters). However, this only worked when the repo was in the github backend and the extra data had been packed for express-download and attached to a release. Now it also works with the normal download methods using the GitHub and GitLab APIs. So, after the move of Suriano from GitHub to GitLab, this functionality is still available. There was a glitch in the layout of the NER tool which caused section labels to be chopped off at the margin, only in notebooks. Thats has been fixed by moving some CSS code from one file to an other. 12.2.7 2024-01-23 There were issues with starting up the Text-Fabric browser: If the system could not start the browser, the TF stopped the webserver. That is not helpful, because one can always open a browser and enter the url in the address bar. Now TF shows the url rather prominently when it does not open a browser. If debug mode is on, Flask reloads the whole process, and that might include opening the browser as well. Now Flask only opens the browser after the startup of the webserver, and not anymore after successive reloads. 12.2.6 2024-01-15 Somehow the express way of downloading data (via complete.zip attached to the latest release) did not get triggered in all cases where it should. It is now triggered in more cases than before. 12.2.5 2023-12-18 Small fix in NER browser: prevent submitting the form if the focus is in a textarea field or in an input field that does not have type=submit. 12.2.3,4 2023-12-09 Writing support for Ugaritic, thanks to Martijn Naaijer and Christian H\u00f8jgaard for converting a Ugaritic corpus to TF. Fix in display functions (continued): The logic of feature display, fixed in the previous version, was not effective when things are displayed in the TF browser. Because in the TF browser the features of the last query were passed as extraFeatures instead of tupleFeatures . This has been fixed by using tupleFeatures in the TF browser as well. 12.2.2 2023-12-02 Fix in display functions, thanks to Tony Jurg: if you do A.pretty(x, queryFeatures=False, extraFeatures=\"yy zz\") the extra features were not shown. So there was no obvious way to control exactly the features that you want to show in a display. That has been fixed. Further clarification: the node features that are used by a query are stored in the display option tupleFeatures . That is what causes them to be displayed in subsequent display statements. You can also explicitly set/pass the tupleFeatures parameter. However, the fact that queryFeatures=False prohibited the display of features mentioned in extraFeatures was against the intuitions. Improvements in the PageXML conversion. There are token features str , after that reflect the logical tokens There are token features rstr , rafter that reflect the physical tokens The distincition between logical and physical is that physical token triplets with the soft hyphen as the middle one, are joined to one logical token; this happens across line boundaries, but also region and page boundaries. 12.2.0,1 2023-11-28 New conversion tool: from PageXML. Still in its infancy. It uses the [PageXML tools](https: github.com/knaw-huc/pagexml) by Marijn Koolen. For an example see [translatin/logic](https: gitlab.huc.knaw.nl/translatin/logic/-/blob/main/tools/convertPlain.ipynb?ref_type=heads). Fix: TF did not fetch an earlier version of a corpus if the newest release contains a complete.zip (which only has the latest version). For some technical reason that still escapes me, the TF browser was slow to start. Fixed it by saying threaded=True to Flask, as suggested on [stackoverflow](https: stackoverflow.com/a/11150849/15236220) From now on: TF does not try to download complete.zip if you pass a version argument to the use() command. 12.1 12.1.6,7 2023-11-15 Various fixes: Some package data was not included for the NER annotation tool. In the NER tool, the highlighting of hits of the search pattern is now exact, it was sometimes off. Deleted tf.tools.docsright again, but developed it further in [docsright](https: github.com/annotation/docsright). 12.1.5 2023-11-02 Improvement in dependencies. Text-Fabric is no longer mandatory dependent on openpyxl , pandas , pyarrow , lxml . The optional dependencies on pygithub and python-gitlab remain, but most users will never need them, because TF can also fetch the complete.zip that is available as release asset for most corpora. Whenever TF invokes a module that is not in the mandatory dependencies, it will act gracefully, providing hints to install the modules in question. 12.1.3,4 2023-11-01 API change in the Annotator: Calling the annotator is now easier: A.makeNer() (No need to make an additional import statement.) This will give you access to all annotation methods, including using a spreadsheet to read annotation instructions from. Removal of deprecated commands (on the command line) in version 11: text-fabric (has become tf ) text-fabric-zip (has become tf-zip ) text-fabric-make (has become tf-make ) Bug fixes: [ 81](https: github.com/annotation/text-fabric/issues/81) and [ 82](https: github.com/annotation/text-fabric/issues/82) Spell-checked all bits of the TF docs here (33,000 lines). Wrote a script tf.tools.docsright to separate the code content from the markdown content, and to strip bits from the markdown content that lead to false positives for the spell checker. Then had the Vim spell checker run over those lines and corrected all mistakes by hand. Still, there might be grammar errors and content inaccuracies. 12.1.4 follows 12.1.3. quickly, because in corpora without a NER configuration file, TF did not start up properly. 12.1.1,2 2023-10-29 Bug fix: the mechanism to make individual exceptions when adding named entities in the tf.browser.ner.annotate tool was broken. Thanks to Daniel Swanson for spotting it. Additional fixes and enhancements. 12.1.0 2023-10-28 New stuff In the TF browser there will be a new tab in the vertical sidebar: Annotate , which will give access to manual annotation tools. I am developing the first one, a tool to annotate named entities efficiently, both in the TF browser and in a Jupyter Notebook. Reed more in tf.about.annotate . These tools will let you save your work as files on your own computer. In tf.convert.addnlp we can now extract more NLP information besides tokens and sentences: part-of-speech, morphological tagging, lemmatisation, named entity recognition Fixes in the TEI converter. 12.0 12.0.6,7 2023-09-13 Trivial fix in code that exports the data from a job in the TF browser. In the meanwhile there is unfinished business in the Annotate tab in the TF browser, that will come into production in the upcoming 12.1 release. The Chrome browser has an attractive feature that other browsers such as Safari lack: It supports the CSS property [content-visibility](https: developer.mozilla.org/en-US/docs/Web/CSS/content-visibility). With this property you can prevent the browser to do the expensive rendering of content that is not visible on the screen. That makes it possible to load a lot of content in a single page without tripping up the browser. You also need the [ IntersectionObserver API](https: developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API), but that is generally supported by browsers. With the help of that API you can restrict the binding of event listeners to elements that are visible on the screen. So, you can open the TF browser in Chrome by passing the option chrome . But if Chrome is not installed, it will open in the default browser anyway. Also, when the opening of the browser fails somehow, the web server is stopped. 12.0.5 2023-07-10 Fixed references to static files that still went to /server instead of /browser . This has to do with the new approach to the TF browser. 12.0.0-4 2023-07-05 Simplification The TF browser no longer works with a separate process that holds the TF corpus data. Instead, the web server (flask) loads the corpus itself. This will restrict the usage of the TF browser to local-single-user scenarios. TF no longer exposes the installation options [browser, pandas] pip install 'text-fabric[browser]' pip install 'text-fabric[pandas]' If you work with Pandas (like exporting to Pandas) you have to install it yourself: pip install pandas pyarrow The TF browser is always supported. The reason to have these distinct capabilities was that there are python libraries involved that do not install on the iPad. The simplification of the TF browser makes it possible to be no longer dependent on these modules. Hence, TF can be installed on the iPad, although the TF browser works is not working there yet. But the auto-downloading of data from GitHub / GitLab works. Minor things Header. After loading a dataset, a header is shown with shows all kinds of information about the corpus. But so far, it did not show the TF app settings. Now they are included in the header. There are two kinds: the explicitly given settings and the derived and computed settings. The latter ones will be suppressed when loading a dataset in a Jupyter notebook, because these settings can become quite big. You can still get them with A.showContext() . In the TF browser they will be always included, you find it in the Corpus tab. - Older releases See tf.about.releasesold ." }, { "ref":"tf.about.clientmanual", @@ -4139,6 +4145,36 @@ INDEX=[ "func":1 }, { +"ref":"tf.browser.ner.sheets.Sheets.showLog", +"url":98, +"doc":"", +"func":1 +}, +{ +"ref":"tf.browser.ner.sheets.Sheets.clearLog", +"url":98, +"doc":"", +"func":1 +}, +{ +"ref":"tf.browser.ner.sheets.Sheets.readLog", +"url":98, +"doc":"", +"func":1 +}, +{ +"ref":"tf.browser.ner.sheets.Sheets.writeLog", +"url":98, +"doc":"", +"func":1 +}, +{ +"ref":"tf.browser.ner.sheets.Sheets.log", +"url":98, +"doc":"", +"func":1 +}, +{ "ref":"tf.browser.ner.sheets.Sheets.processSheet", "url":98, "doc":"Generates derived data structures out of the source sheet. After loading we process the set into derived data structures. We try to be lazy. We only load a set from disk if it is not already in memory, or if the set on disk has been updated since the last load. The resulting data is stored in the current set under the various keys. After processing, the time of processing is recorded, so that it can be observed if the processed set is no longer up to date w.r.t. the source. For each such set we produce several data structures, which we store under the following keys: dateProcessed : datetime when the set was last processed entityText : dict, text of entity by entity node or line number in TSV file; inventory : result of looking up all triggers Parameters changed: boolean Whether the set has changed since last processing.", @@ -4416,7 +4452,7 @@ INDEX=[ { "ref":"tf.browser.ner.serve.Serve.wrapSets", "url":102, -"doc":"HTML for the annotation set chooser. It is a list of buttons, each corresponding to an existing annotation set. A click on the button selects that set. There is also a control to delete the set. Apart from these buttons there is a button to switch to the entities that are present in the TF dataset as nodes of the entity type specified in the YAML file with corresponding features. Finally, it is possible to create a new, empty annotation set.", +"doc":"HTML for the annotation set chooser. It is a dropdown with options, each corresponding to an existing annotation set. There is also a control to delete the set. Apart from these buttons there is a button to switch to the entities that are present in the TF dataset as nodes of the entity type specified in the YAML file with corresponding features. Finally, it is possible to create a new, empty annotation set.", "func":1 }, { @@ -4582,7 +4618,7 @@ INDEX=[ { "ref":"tf.browser.ner.ner", "url":103, -"doc":"API for Named Entity marking. As a preparation, read tf.about.annotate first, since it explains the concepts, and guides you to set up the configuration for your corpus. The main task of this module is to find occurrences of annotations on the basis of criteria. But this is just the tip of the iceberg, since this module inherits from a number of other modules that inherit form yet other modules: tf.browser.ner.show : generate HTML for annotated buckets of the corpus; tf.browser.ner.sets : manage annotation sets; tf.browser.ner.data : manage annotation data: loading, adding/deleting annotations; tf.browser.ner.settings : manage the specifics of a TF corpus and have access to its data. It also uses tf.browser.ner.match : to filter individual buckets on the basis of criteria. Hence, Annotation is the central class of this tool, whose methods are relevant for: tf.browser.ner.ner : the API for users to manipulate annotations in their own programs, especially in a Jupyter notebook. tf.browser.ner.web : Flask app that routes URLs to controller functions. web makes use of the following modules that are not needed by ner : tf.browser.ner.serve : define the controllers of the web app Again, this is a top of an iceberg, since it inherits from: tf.browser.ner.request : manage the data of a request; tf.browser.ner.fragments : generate HTML for widgets on the page; request also uses form to retrieve form values into typed and structured values. Both web and ner make use of the following modules in as far as they are not already mentioned under annotate and its parent classes: tf.browser.ner.helpers : a variety of context-free data jugglers; tf.browser.html : a generic library to generate HTML using Pythonic syntax. This module contains the top-level methods for applying annotation rules to a corpus. ! note \"Class hierarchy\" The classes Settings , Corpus , Data , Sets , Show , NER form one hierarchy. So an object of class NER has access to all methods of these classes. The classes Serve , Request , Fragments , From form a separate hierarchy. It will create an NER instance which will be stored in a Serve instance. Here is an overview how the modules hang together. A | denotes inheritance, parent classes above child classes. A <-< arrow denotes dependency by importing code. Browser | Api-hierarchy web < -< Serve < -< NER <-< match | | | | Request Fragments <-< html | Sets Sheets Show <-< html | | | Form | Data | | | Corpus | | | Settings Programmatic annotation done in a Jupyter Notebook If you have a spreadsheet with named entities, and for each entity a list of surface forms, then this module takes care to read that spreadsheet, translate it to YAML, and then use the YAML as instructions to add entity annotations to the corpus. See this [example notebook](https: nbviewer.jupyter.org/github/HuygensING/suriano/blob/main/programs/ner.ipynb). Here are more details. Starting up Load the relevant Python modules: python from tf.app import use Load your corpus. There are two ways: Work with a local GitHub clone of the corpus in ~/HuygensING/suriano : A = use(\"HuygensING/suriano:clone\", checkout=\"clone\") Or let TF auto-download the latest version and work with that: A = use(\"HuygensING/suriano\") Load the Ner module: python NE = A.makeNer() The tool expects some input data to be present: configuration and spreadsheets with instructions. They can be found in the ner directory. If you work with a local GitHub clone, that data resides in ~/github/HuygensING/suriano and if you work with an auto-downloaded copy of the data, it is in ~/text-fabric-data/github/HuygensING/suriano . The output data of the tool ends up in the _temp directory, which ends up next to the ner directory. The entity spreadsheets Here is an example: ![browser]( / /images/Ner/spreadsheet.png) In our example, the name of the spreadsheet containing this information is people.xlsx and it can be found as ner/sheets/people.xlsx The spreadsheet will be read as follows: the first two rows will be skipped after that, each row is taken to describe exactly one entity the first column has the full and unique name for that entity the second column contains the kind of the entity (you may choose your keywords freely for this) the third column contains a number of surface forms for this entity, separated by ; when the surface forms are peeled out, leading and trailing white-space will be stripped all other columns will be ignored for the moment; in later versions we may use the information in those columns to fill in extra data about the entities; but probably that information will not end up in TF features. During translation from XLSX to YAML the following happens: An identifier is distilled from the name of the entity; Missing kind fields are filled with the default kind. These steps need some configuration information from the ner/config.yaml file. Translation is done by python NE.setSheet(\"people\") The resulting YAML ends up next to the spreadsheet, and it looks like this: yaml christoffel.sticke: kind: PER name: Christoffel Sticke occSpecs: [] diederik.sticke: kind: PER name: Diederik Sticke occSpecs: - Dierck - Dirk dirck.hartog: kind: PER name: Dirck Hartog occSpecs: - Dirich Hartocson - Hertocson jan.baptist.roelants: kind: PER name: Jan-Baptist Roelants occSpecs: - Roelans - Rolans Inventory A first step is to find out how many occurrences we find in the corpus for these surface forms: python NE.lookup() NE.showHits() and the output looks like this . cornelis.adriaensz PER Pach 7 x Cornelis Adriaensz. Pack david.marlot PER Morlot 1 x David de Marlot erick.dimmer PER Dimer 11 x Erick Dimmer erycius.puteanus PER Potiano 2 x Erycius Puteanus francesco.giustiniani PER Giustiniano 11 x Francesco Giustiniani francois.doubleth PER Doublet 2 x Fran\u00e7ois Doubleth . Total 150 Entities that are in the spreadsheet, but not in the corpus are skipped. Marking up In order to create annotations for these entities, we have to switch to an annotation set. Let's start a new set and give it the name power . python NE.setSet(\"power\") If it turns out that power has already annotations, and you want to clear them, say python NE.resetSet(\"power\") Now we are ready for the big thing: creating the annotations: python NE.markEntities() It outputs this message: Already present: 0 x Added: 150 x Inspection We now revert to lower-level methods from the tf.browser.ner.ner class to inspect some of the results. python results = NE.filterContent(bFind=\"pach\", bFindC=False, anyEnt=True, showStats=None) Here we filtered the chunks (paragraphs) to those that contain the string pach , in a case-insensitive way, and that contain at least one entity. There 6 of them, and we can show them: python NE.showContent(results) ![browser]( / /images/Ner/pach.png) The resulting entities are in _temp/power/entities.tsv and look like this: erick.dimmer PER 160196 isabella.clara.eugenia PER 142613 gaspar.iii.coligny PER 7877 isabella.clara.eugenia PER 210499 john.vere PER 94659 antonio.lando PER 267755 isabella.clara.eugenia PER 107069 isabella.clara.eugenia PER 9162 michiel.pagani PER 94366 isabella.clara.eugenia PER 179208 isabella.clara.eugenia PER 258933 hans.meinhard PER 75039 . Each line corresponds to a marked entity occurrence. Lines consist of tab separated fields: entity identifier entity kind remaining fields: slots, i.e. the textual positions occupied by the occurrence. Some entity occurrences consist of multiple words / tokens, hence have multiple slots." +"doc":"API for Named Entity marking. As a preparation, read tf.about.annotate first, since it explains the concepts, and guides you to set up the configuration for your corpus. The main task of this module is to find occurrences of annotations on the basis of criteria. But this is just the tip of the iceberg, since this module inherits from a number of other modules that inherit form yet other modules: tf.browser.ner.show : generate HTML for annotated buckets of the corpus; tf.browser.ner.sets : manage annotation sets; tf.browser.ner.data : manage annotation data: loading, adding/deleting annotations; tf.browser.ner.settings : manage the specifics of a TF corpus and have access to its data. It also uses tf.browser.ner.match : to filter individual buckets on the basis of criteria. Hence, Annotation is the central class of this tool, whose methods are relevant for: tf.browser.ner.ner : the API for users to manipulate annotations in their own programs, especially in a Jupyter notebook. tf.browser.ner.web : Flask app that routes URLs to controller functions. web makes use of the following modules that are not needed by ner : tf.browser.ner.serve : define the controllers of the web app Again, this is a top of an iceberg, since it inherits from: tf.browser.ner.request : manage the data of a request; tf.browser.ner.fragments : generate HTML for widgets on the page; request also uses form to retrieve form values into typed and structured values. Both web and ner make use of the following modules in as far as they are not already mentioned under annotate and its parent classes: tf.browser.ner.helpers : a variety of context-free data jugglers; tf.browser.html : a generic library to generate HTML using Pythonic syntax. This module contains the top-level methods for applying annotation rules to a corpus. ! note \"Class hierarchy\" The classes Settings , Corpus , Data , Sets , Show , NER form one hierarchy. So an object of class NER has access to all methods of these classes. The classes Serve , Request , Fragments , From form a separate hierarchy. It will create an NER instance which will be stored in a Serve instance. Here is an overview how the modules hang together. A | denotes inheritance, parent classes above child classes. A <-< arrow denotes dependency by importing code. Browser | Api-hierarchy web < -< Serve < -< NER <-< match | | | | Request Fragments <-< html | Sets Sheets Show <-< html | | | Form | Data | | | Corpus | | | Settings Programmatic annotation done in a Jupyter Notebook If you have a spreadsheet with named entities, and for each entity a list of surface forms, then this module takes care to read that spreadsheet, translate it to YAML, and then use the YAML as instructions to add entity annotations to the corpus. See this [example notebook](https: nbviewer.jupyter.org/github/HuygensING/suriano/blob/main/programs/ner.ipynb). Here are more details. Starting up Load the relevant Python modules: python from tf.app import use Load your corpus. There are two ways: Work with a local GitHub clone of the corpus in ~/HuygensING/suriano : A = use(\"HuygensING/suriano:clone\", checkout=\"clone\") Or let TF auto-download the latest version and work with that: A = use(\"HuygensING/suriano\") Load the Ner module: python NE = A.makeNer() The tool expects some input data to be present: configuration and spreadsheets with instructions. They can be found in the ner directory. If you work with a local GitHub clone, that data resides in ~/github/HuygensING/suriano and if you work with an auto-downloaded copy of the data, it is in ~/text-fabric-data/github/HuygensING/suriano . The output data of the tool ends up in the _temp directory, which ends up next to the ner directory. The entity spreadsheets Here is an example: ![browser]( / /images/Ner/spreadsheet.png) In our example, the name of the spreadsheet containing this information is people.xlsx and it can be found as ner/sheets/people.xlsx The spreadsheet will be read as follows: the first two rows will be skipped after that, each row is taken to describe exactly one entity the first column has the full and unique name for that entity the second column contains the kind of the entity (you may choose your keywords freely for this) the third column contains a number of surface forms for this entity, separated by ; when the surface forms are peeled out, leading and trailing white-space will be stripped all other columns will be ignored for the moment; in later versions we may use the information in those columns to fill in extra data about the entities; but probably that information will not end up in TF features. During translation from XLSX to YAML the following happens: An identifier is distilled from the name of the entity; Missing kind fields are filled with the default kind. These steps need some configuration information from the ner/config.yaml file. Translation is done by python NE.setSheet(\"people\") The resulting YAML ends up next to the spreadsheet, and it looks like this: yaml christoffel.sticke: kind: PER name: Christoffel Sticke occSpecs: [] diederik.sticke: kind: PER name: Diederik Sticke occSpecs: - Dierck - Dirk dirck.hartog: kind: PER name: Dirck Hartog occSpecs: - Dirich Hartocson - Hertocson jan.baptist.roelants: kind: PER name: Jan-Baptist Roelants occSpecs: - Roelans - Rolans Inventory A first step is to find out how many occurrences we find in the corpus for these surface forms: python NE.reportHits() and the output looks like this . cornelis.adriaensz PER Pach 7 x Cornelis Adriaensz. Pack david.marlot PER Morlot 1 x David de Marlot erick.dimmer PER Dimer 11 x Erick Dimmer erycius.puteanus PER Potiano 2 x Erycius Puteanus francesco.giustiniani PER Giustiniano 11 x Francesco Giustiniani francois.doubleth PER Doublet 2 x Fran\u00e7ois Doubleth . Total 150 Entities that are in the spreadsheet, but not in the corpus are skipped. Inspection We now revert to lower-level methods from the tf.browser.ner.ner class to inspect some of the results. python results = NE.filterContent(bFind=\"pach\", bFindC=False, anyEnt=True, showStats=None) Here we filtered the chunks (paragraphs) to those that contain the string pach , in a case-insensitive way, and that contain at least one entity. There 6 of them, and we can show them: python NE.showContent(results) ![browser]( / /images/Ner/pach.png) The resulting entities are in _temp/power/entities.tsv and look like this: erick.dimmer PER 160196 isabella.clara.eugenia PER 142613 gaspar.iii.coligny PER 7877 isabella.clara.eugenia PER 210499 john.vere PER 94659 antonio.lando PER 267755 isabella.clara.eugenia PER 107069 isabella.clara.eugenia PER 9162 michiel.pagani PER 94366 isabella.clara.eugenia PER 179208 isabella.clara.eugenia PER 258933 hans.meinhard PER 75039 . Each line corresponds to a marked entity occurrence. Lines consist of tab separated fields: entity identifier entity kind remaining fields: slots, i.e. the textual positions occupied by the occurrence. Some entity occurrences consist of multiple words / tokens, hence have multiple slots." }, { "ref":"tf.browser.ner.ner.NER", @@ -4614,12 +4650,6 @@ INDEX=[ "func":1 }, { -"ref":"tf.browser.ner.ner.NER.markEntities", -"url":103, -"doc":"Marks up the members of the inventory as entities. The instructions contain the entity identifier and the entity kind that have to be assigned to the surface forms. The inventory knows where the occurrences of the surface forms are. If there is no inventory yet, it will be created.", -"func":1 -}, -{ "ref":"tf.browser.ner.ner.NER.bakeEntities", "url":103, "doc":"Bakes the entities of the current set as nodes into a new TF data source. Parameters versionExtension: string, optional \"e\" The new dataset gets a version like the original dataset, but extended with this string.", @@ -4703,7 +4733,7 @@ INDEX=[ { "ref":"tf.browser.ner.ner.NER.setDup", "url":104, -"doc":"Duplicates the current set to a set with a new name. ! hint \"The special set can be duplicated\" After duplication of the special read-only set, the duplicate copy is modifiable. In this way you can make corrections to the set of pre-existing, tool-generated annotations. The current set changes to the result of the duplication. Parameters dupSet: string The name of new set that is the result of the duplication.", +"doc":"Duplicates the current set to a set with a new name. ! hint \"The readonly sets can be duplicated\" After duplication of a read-only set, the duplicate copy is modifiable. In this way you can make corrections to the set of pre-existing, tool-generated annotations. The current set changes to the result of the duplication. Parameters dupSet: string The name of new set that is the result of the duplication.", "func":1 }, { @@ -4724,11 +4754,6 @@ INDEX=[ "doc":"The current annotation set." }, { -"ref":"tf.browser.ner.ner.NER.setNameRep", -"url":104, -"doc":"The name representation of the current annotation set." -}, -{ "ref":"tf.browser.ner.ner.NER.setNames", "url":104, "doc":"The set of names of annotation sets that are present on the file system." @@ -4772,7 +4797,7 @@ INDEX=[ { "ref":"tf.browser.ner.ner.NER.addEntities", "url":105, -"doc":"Add multiple entities efficiently to the current set. This operation is not allowed if the current set is the read-only set with the empty name. If you have multiple entities to add, it is wasteful to do multiple passes over the corpus to find them. This method does them all in one fell swoop. It is used by the method tf.browser.ner.ner.NER.markEntities() . Parameters newEntites: iterable of tuples of tuples each new entity consists of a tuple of entity feature values, specifying the entity to add a list of slot tuples, specifying where to add this entity silent: boolean, optional False Reports how many entities have been added and how many were already present in the specified locations. Returns - (int, int) or void If silent , it returns the number of already existing entities that were asked to be deleted and the number of actually deleted entities. If the operation is not allowed, both integers above are set to -1.", +"doc":"Add multiple entities efficiently to the current set. This operation is not allowed if the current set is the read-only set with the empty name. If you have multiple entities to add, it is wasteful to do multiple passes over the corpus to find them. This method does them all in one fell swoop. Parameters newEntites: iterable of tuples of tuples each new entity consists of a tuple of entity feature values, specifying the entity to add a list of slot tuples, specifying where to add this entity silent: boolean, optional False Reports how many entities have been added and how many were already present in the specified locations. Returns - (int, int) or void If silent , it returns the number of already existing entities that were asked to be deleted and the number of actually deleted entities. If the operation is not allowed, both integers above are set to -1.", "func":1 }, { @@ -5029,7 +5054,19 @@ INDEX=[ { "ref":"tf.browser.ner.fragments.Fragments.wrapSets", "url":102, -"doc":"HTML for the annotation set chooser. It is a list of buttons, each corresponding to an existing annotation set. A click on the button selects that set. There is also a control to delete the set. Apart from these buttons there is a button to switch to the entities that are present in the TF dataset as nodes of the entity type specified in the YAML file with corresponding features. Finally, it is possible to create a new, empty annotation set.", +"doc":"HTML for the annotation set chooser. It is a dropdown with options, each corresponding to an existing annotation set. There is also a control to delete the set. Apart from these buttons there is a button to switch to the entities that are present in the TF dataset as nodes of the entity type specified in the YAML file with corresponding features. Finally, it is possible to create a new, empty annotation set.", +"func":1 +}, +{ +"ref":"tf.browser.ner.fragments.Fragments.wrapCaption", +"url":102, +"doc":"", +"func":1 +}, +{ +"ref":"tf.browser.ner.fragments.Fragments.wrapLogs", +"url":102, +"doc":"", "func":1 }, { @@ -5130,7 +5167,13 @@ INDEX=[ { "ref":"tf.browser.ner.sets.Sets", "url":104, -"doc":"Methods to create, duplicate, rename and delete annotation sets. Annotation sets have names, given by the user. There is one special annotation set, whose name is the empty string, and whose content are the pre-existing entities, i.e. the entities that are present in the TF data as nodes and features. There is always one current annotation set, whose data is loaded into memory. Parameters sets: object, optional None Entity sets to start with. If None, a fresh store of sets will be created by a parent class (Data)." +"doc":"Methods to create, duplicate, rename and delete annotation sets. Annotation sets have names, given by the user. There is a special annotation set, whose name is the empty string, and whose content are the pre-existing entities, i.e. the entities that are present in the TF data as nodes and features. Users can not name sets with names that start with a dot. Annotation sets whose name start with a dot are generated by the system when a family of spreadsheets with entity triggers is processed. These sets are readonly, like the special annotation set, but they can be duplicated to ordinary sets. Those copies loose the relationship with the original spreadsheet. There is always one current annotation set, whose data is loaded into memory. Parameters sets: object, optional None Entity sets to start with. If None, a fresh store of sets will be created by a parent class (Data)." +}, +{ +"ref":"tf.browser.ner.sets.Sets.setInfo", +"url":104, +"doc":"", +"func":1 }, { "ref":"tf.browser.ner.sets.Sets.readSets", @@ -5159,7 +5202,7 @@ INDEX=[ { "ref":"tf.browser.ner.sets.Sets.setDup", "url":104, -"doc":"Duplicates the current set to a set with a new name. ! hint \"The special set can be duplicated\" After duplication of the special read-only set, the duplicate copy is modifiable. In this way you can make corrections to the set of pre-existing, tool-generated annotations. The current set changes to the result of the duplication. Parameters dupSet: string The name of new set that is the result of the duplication.", +"doc":"Duplicates the current set to a set with a new name. ! hint \"The readonly sets can be duplicated\" After duplication of a read-only set, the duplicate copy is modifiable. In this way you can make corrections to the set of pre-existing, tool-generated annotations. The current set changes to the result of the duplication. Parameters dupSet: string The name of new set that is the result of the duplication.", "func":1 }, { @@ -5180,11 +5223,6 @@ INDEX=[ "doc":"The current annotation set." }, { -"ref":"tf.browser.ner.sets.Sets.setNameRep", -"url":104, -"doc":"The name representation of the current annotation set." -}, -{ "ref":"tf.browser.ner.sets.Sets.setNames", "url":104, "doc":"The set of names of annotation sets that are present on the file system." @@ -5228,7 +5266,7 @@ INDEX=[ { "ref":"tf.browser.ner.sets.Sets.addEntities", "url":105, -"doc":"Add multiple entities efficiently to the current set. This operation is not allowed if the current set is the read-only set with the empty name. If you have multiple entities to add, it is wasteful to do multiple passes over the corpus to find them. This method does them all in one fell swoop. It is used by the method tf.browser.ner.ner.NER.markEntities() . Parameters newEntites: iterable of tuples of tuples each new entity consists of a tuple of entity feature values, specifying the entity to add a list of slot tuples, specifying where to add this entity silent: boolean, optional False Reports how many entities have been added and how many were already present in the specified locations. Returns - (int, int) or void If silent , it returns the number of already existing entities that were asked to be deleted and the number of actually deleted entities. If the operation is not allowed, both integers above are set to -1.", +"doc":"Add multiple entities efficiently to the current set. This operation is not allowed if the current set is the read-only set with the empty name. If you have multiple entities to add, it is wasteful to do multiple passes over the corpus to find them. This method does them all in one fell swoop. Parameters newEntites: iterable of tuples of tuples each new entity consists of a tuple of entity feature values, specifying the entity to add a list of slot tuples, specifying where to add this entity silent: boolean, optional False Reports how many entities have been added and how many were already present in the specified locations. Returns - (int, int) or void If silent , it returns the number of already existing entities that were asked to be deleted and the number of actually deleted entities. If the operation is not allowed, both integers above are set to -1.", "func":1 }, { @@ -5466,7 +5504,13 @@ INDEX=[ "func":1 }, { -"ref":"tf.browser.ner.helpers.log", +"ref":"tf.browser.ner.helpers.consoleLine", +"url":108, +"doc":"", +"func":1 +}, +{ +"ref":"tf.browser.ner.helpers.repSet", "url":108, "doc":"", "func":1 @@ -5520,7 +5564,7 @@ INDEX=[ { "ref":"tf.browser.ner.data.Data.addEntities", "url":105, -"doc":"Add multiple entities efficiently to the current set. This operation is not allowed if the current set is the read-only set with the empty name. If you have multiple entities to add, it is wasteful to do multiple passes over the corpus to find them. This method does them all in one fell swoop. It is used by the method tf.browser.ner.ner.NER.markEntities() . Parameters newEntites: iterable of tuples of tuples each new entity consists of a tuple of entity feature values, specifying the entity to add a list of slot tuples, specifying where to add this entity silent: boolean, optional False Reports how many entities have been added and how many were already present in the specified locations. Returns - (int, int) or void If silent , it returns the number of already existing entities that were asked to be deleted and the number of actually deleted entities. If the operation is not allowed, both integers above are set to -1.", +"doc":"Add multiple entities efficiently to the current set. This operation is not allowed if the current set is the read-only set with the empty name. If you have multiple entities to add, it is wasteful to do multiple passes over the corpus to find them. This method does them all in one fell swoop. Parameters newEntites: iterable of tuples of tuples each new entity consists of a tuple of entity feature values, specifying the entity to add a list of slot tuples, specifying where to add this entity silent: boolean, optional False Reports how many entities have been added and how many were already present in the specified locations. Returns - (int, int) or void If silent , it returns the number of already existing entities that were asked to be deleted and the number of actually deleted entities. If the operation is not allowed, both integers above are set to -1.", "func":1 }, { @@ -5787,12 +5831,6 @@ INDEX=[ "func":1 }, { -"ref":"tf.browser.ner.match.occMatchOld", -"url":109, -"doc":"Finds the occurrences of multiple sequences of tokens in a single bucket. Parameters getTokens: function See tf.browser.ner.corpus.Corpus.getTokens b: integer The node of the bucket in question qSeqs: set, optional set() A set of sequences of tokens. Each sequence in the set will be used as a search pattern, and it occurrences in the bucket are collected. result: dict A dictionary to collect the results in. Keyed by each member of parameter qSeqs the values are the occurrences of that member in the corpus. A single occurrence is represented as a tuple of slots.", -"func":1 -}, -{ "ref":"tf.browser.ner.match.entityMatch", "url":109, "doc":"Checks whether a bucket satisfies a variety of criteria. When we do the checking, we ignore empty tokens in the bucket. Parameters entityIndex, eStarts, entitySlotVal, entitySlotAll, entitySlotIndex: object Various kinds of processed entity data, see tf.browser.ner.data getTextR: function See tf.browser.ner.corpus.Corpus.getTextR getTokens: function See tf.browser.ner.corpus.Corpus.getTokens b: integer The node of the bucket in question bFindRe, anyEnt, eVals, qTokens, valSelect, freeState: object As in tf.browser.ner.ner.NER.filterContent Returns - tuple Members: fits : boolean, whether the bucket passes the filter (tokens, matches, positions) : tokens all tokens of the bucket, each token is a tuple consisting of its slot number (position) and string value; matches : a list of the positions of the found occurrences for the qTokens and / or eVals in the bucket; positions : a set of positions in the bucket where the bFindRe starts to match;", @@ -6266,7 +6304,7 @@ INDEX=[ { "ref":"tf.cheatsheet", "url":117, -"doc":" A. Advanced API Initialization, configuration, meta data, and linking python A = use('org/repo') : start up and load a corpus from a repository and deliver its API. : See tf.about.usefunc python A.hoist(globals( : Make the API handles F , E , T , L etc available in the global scope. : tf.advanced.app.App.load python A.load(features) : Load an extra bunch of features. : tf.advanced.app.App.load python A.showContext( .) : show app settings : tf.advanced.settings.showContext python A.header(allMeta=False) : show colophon : tf.advanced.links.header python A.showProvenance( .) : show provenance of code and data : tf.advanced.links.showProvenance python A.webLink(n, .) : hyperlink to node n on the web : tf.advanced.links.webLink python A.flexLink(\"pages\") A.flexLink(\"tut\") : hyperlink to app tutorial and documentation : tf.advanced.links.flexLink python A.isLoaded(features=None) : Show information about loaded features : tf.core.api.Api.isLoaded python A.footprint() : Show memory footprint per feature : tf.core.api.Api.footprint - Displaying python A.specialCharacters() : show all hard-to-type characters in the corpus in a widget : tf.advanced.text.specialCharacters python A.showFormats() : show all text formats and their definitions : tf.advanced.text.showFormats python A.dm(markdownString) : display markdown string in notebook : tf.advanced.helpers.dm python A.dh(htmlString) : display HTML string in notebook : tf.advanced.helpers.dh python A.method(option1=value1, option2=value2, .) : Many of the following methods accept these options as keyword arguments: : tf.advanced.options python A.displayShow( .) : show display options : tf.advanced.display.displayShow python A.displayReset( .) : reset display options : tf.advanced.display.displayReset python A.displaySetup( .) : set up display options : tf.advanced.display.displaySetup python A.table(results, .) : plain rendering of tuple of tuples of node : tf.advanced.display.table python A.plainTuple(tup, .) : plain rendering of tuple of node : tf.advanced.display.plainTuple python A.plain(node, .) : plain rendering of node : tf.advanced.display.plain python A.show(results, .) : pretty rendering of tuple of tuples of node : tf.advanced.display.show python A.prettyTuple(tup, .) : pretty rendering of tuple of node : tf.advanced.display.prettyTuple python A.pretty(node, .) : pretty rendering of node : tf.advanced.display.pretty python A.unravel(node, .) : convert a graph to a tree : tf.advanced.unravel.unravel python A.getCss() : get the complete CSS style sheet for this app : tf.advanced.display.getCss - Search (high level) python A.search( .) : search, collect and deliver results, report number of results : tf.advanced.search.search - Sections and Structure python A.nodeFromSectionStr( .) : lookup node for section heading : tf.advanced.sections.nodeFromSectionStr python A.sectionStrFromNode( .) : lookup section heading for node : tf.advanced.sections.sectionStrFromNode python A.structureStrFromNode( .) : lookup structure heading for node : tf.advanced.sections.structureStrFromNode - Volumes and collections See also tf.about.volumes . python A.getVolumes() : list all volumes of this dataset : tf.fabric.Fabric.getVolumes python A.extract(volumes, .) : export volumes based on a volume specification : tf.fabric.Fabric.extract python A.collect(volumes, .) : collect several volumes into a new collection : tf.advanced.display.export : tf.fabric.Fabric.collect - Export to Excel python A.export(results, .) : export formatted data : tf.advanced.display.export - Logging python A.dm(markdownString) : display markdown string in notebook : tf.advanced.helpers.dm python A.dh(htmlString) : display HTML string in notebook : tf.advanced.helpers.dh python A.version : version number of data of the corpus. : tf.fabric.Fabric.version The following methods work also for TF. instead of A. : python A.banner : banner of the TF program. : tf.fabric.Fabric.banner python A.isSilent() : report the verbosity of TF : tf.core.timestamp.Timestamp.isSilent python A.silentOn(deep=False) : make TF (deeply) silent from now on. : tf.core.timestamp.Timestamp.silentOn python A.silentOff() : make TF talkative from now on. : tf.core.timestamp.Timestamp.silentOff python A.setSilent(silent) : set the verbosity of TF. : tf.core.timestamp.Timestamp.setSilent python A.indent(level=None, reset=False) : Sets up indentation and timing of following messages : tf.core.timestamp.Timestamp.indent python A.info(msg, tm=True, nl=True, .) : informational message : tf.core.timestamp.Timestamp.info python A.warning(msg, tm=True, nl=True, .) : warning message : tf.core.timestamp.Timestamp.warning python A.error(msg, tm=True, nl=True, .) : error message : tf.core.timestamp.Timestamp.error - N. F. E. L. T. S. C. Core API N. Nodes Read about the canonical ordering here: tf.core.nodes . python N.walk() : generator of all nodes in canonical ordering : tf.core.nodes.Nodes.walk python N.sortNodes(nodes) : sorts nodes in the canonical ordering : tf.core.nodes.Nodes.sortNodes python N.otypeRank[nodeType] : ranking position of nodeType : tf.core.nodes.Nodes.otypeRank python N.sortKey(node) : defines the canonical ordering on nodes : tf.core.nodes.Nodes.sortKey python N.sortKeyTuple(tup) : extends the canonical ordering on nodes to tuples of nodes : tf.core.nodes.Nodes.sortKeyTuple python N.sortKeyChunk(node) : defines the canonical ordering on node chunks : tf.core.nodes.Nodes.sortKeyChunk - F. Node features python Fall() : all loaded feature names (node features only) : tf.core.api.Api.Fall python F.fff.v(node) : get value of node feature fff : tf.core.nodefeature.NodeFeature.v python F.fff.s(value) : get nodes where feature fff has value : tf.core.nodefeature.NodeFeature.s python F.fff.freqList( .) : frequency list of values of fff : tf.core.nodefeature.NodeFeature.freqList python F.fff.items( .) : generator of all entries of fff as mapping from nodes to values : tf.core.nodefeature.NodeFeature.items python F.fff.meta : meta data of feature fff : tf.core.nodefeature.NodeFeature.meta python Fs('fff') : identical to F.ffff , usable if name of feature is variable : tf.core.api.Api.Fs - Special node feature otype Maps nodes to their types. python F.otype.v(node) : get type of node : tf.core.otypefeature.OtypeFeature.v python F.otype.s(nodeType) : get all nodes of type nodeType : tf.core.otypefeature.OtypeFeature.s python F.otype.sInterval(nodeType) : gives start and ending nodes of nodeType : tf.core.otypefeature.OtypeFeature.sInterval python F.otype.items( .) : generator of all (node, type) pairs. : tf.core.otypefeature.OtypeFeature.items python F.otype.meta : meta data of feature otype : tf.core.otypefeature.OtypeFeature.meta python F.otype.maxSlot : the last slot node : tf.core.otypefeature.OtypeFeature.maxSlot python F.otype.maxNode : the last node : tf.core.otypefeature.OtypeFeature.maxNode python F.otype.slotType : the slot type : tf.core.otypefeature.OtypeFeature.slotType python F.otype.all : sorted list of all node types : tf.core.otypefeature.OtypeFeature.all - E. Edge features python Eall() : all loaded feature names (edge features only) : tf.core.api.Api.Eall python E.fff.f(node) : get value of feature fff for edges from node : tf.core.edgefeature.EdgeFeature.f python E.fff.t(node) : get value of feature fff for edges to node : tf.core.edgefeature.EdgeFeature.t python E.fff.freqList( .) : frequency list of values of fff : tf.core.edgefeature.EdgeFeature.freqList python E.fff.items( .) : generator of all entries of fff as mapping from edges to values : tf.core.edgefeature.EdgeFeature.items python E.fff.b(node) : get value of feature fff for edges from and to node : tf.core.edgefeature.EdgeFeature.b python E.fff.meta : all meta data of feature fff : tf.core.edgefeature.EdgeFeature.meta python Es('fff') : identical to E.fff , usable if name of feature is variable : tf.core.api.Api.Es - Special edge feature oslots Maps nodes to the set of slots they occupy. python E.oslots.items( .) : generator of all entries of oslots as mapping from nodes to sets of slots : tf.core.oslotsfeature.OslotsFeature.items python E.oslots.s(node) : set of slots linked to node : tf.core.oslotsfeature.OslotsFeature.s python E.oslots.meta : all meta data of feature oslots : tf.core.oslotsfeature.OslotsFeature.meta - L. Locality python L.i(node, otype= .) : go to intersecting nodes : tf.core.locality.Locality.i python L.u(node, otype= .) : go one level up : tf.core.locality.Locality.u python L.d(node, otype= .) : go one level down : tf.core.locality.Locality.d python L.p(node, otype= .) : go to adjacent previous nodes : tf.core.locality.Locality.p python L.n(node, otype= .) : go to adjacent next nodes : tf.core.locality.Locality.n - T. Text python T.text(node, fmt= ., .) : give formatted text associated with node : tf.core.text.Text.text - Sections Rigid 1 or 2 or 3 sectioning system python T.sectionTuple(node) : give tuple of section nodes that contain node : tf.core.text.Text.sectionTuple python T.sectionFromNode(node) : give section heading of node : tf.core.text.Text.sectionFromNode python T.nodeFromSection(section) : give node for section heading : tf.core.text.Text.nodeFromSection - Structure Flexible multilevel sectioning system python T.headingFromNode(node) : give structure heading of node : tf.core.text.Text.headingFromNode python T.nodeFromHeading(heading) : give node for structure heading : tf.core.text.Text.nodeFromHeading python T.structureInfo() : give summary of dataset structure : tf.core.text.Text.structureInfo python T.structure(node) : give structure of node and all in it. : tf.core.text.Text.structure python T.structurePretty(node) : pretty print structure of node and all in it. : tf.core.text.Text.structurePretty python T.top() : give all top-level structural nodes in the dataset : tf.core.text.Text.top python T.up(node) : gives parent of structural node : tf.core.text.Text.up python T.down(node) : gives children of structural node : tf.core.text.Text.down - S. Search (low level) [ searchRough ](https: nbviewer.jupyter.org/github/ETCBC/bhsa/blob/master/tutorial/searchRough.ipynb) Preparation python S.search(query, limit=None) : Query the TF dataset with a template : tf.search.search.Search.search python S.study(query, .) : Study the query in order to set up a plan : tf.search.search.Search.study python S.showPlan(details=False) : Show the search plan resulting from the last study. : tf.search.search.Search.showPlan python S.relationsLegend() : Catalog of all relational devices in search templates : tf.search.search.Search.relationsLegend - Fetching results python S.count(progress=None, limit=None) : Count the results, up to a limit : tf.search.search.Search.count python S.fetch(limit=None, .) : Fetches the results, up to a limit : tf.search.search.Search.fetch python S.glean(tup) : Renders a single result into something human readable. : tf.search.search.Search.glean - Implementation python S.tweakPerformance( .) : Set certain parameters that influence the performance of search. : tf.search.search.Search.tweakPerformance - C. Computed data components. Access to pre-computed data: tf.core.computed.Computeds . All components have just one useful attribute: .data . python Call() : all pre-computed data component names : tf.core.api.Api.Call python Cs('ccc') : identical to C.ccc , usable if name of component is variable : tf.core.api.Api.Cs python C.levels.data : various statistics on node types : tf.core.prepare.levels python C.order.data : the canonical order of the nodes ( tf.core.nodes ) : tf.core.prepare.order python C.rank.data : the rank of the nodes in the canonical order ( tf.core.nodes ) : tf.core.prepare.rank python C.levUp.data : feeds the tf.core.locality.Locality.u function : tf.core.prepare.levUp python C.levDown.data : feeds the tf.core.locality.Locality.d function : tf.core.prepare.levDown python C.boundary.data : feeds the tf.core.locality.Locality.p and tf.core.locality.Locality.n functions : tf.core.prepare.boundary python C.characters.data : frequency list of characters in a corpus, separately for all the text formats : tf.core.prepare.characters python C.sections.data : feeds the section part of tf.core.text : tf.core.prepare.sections python C.structure.data : feeds the structure part of tf.core.text : tf.core.prepare.structure - TF. Dataset Loading python TF = Fabric(locations=dirs, modules=subdirs, volume=None, collection=None, silent=\"auto\") : Initialize API on work or single volume or collection of a work from explicit directories. Use tf.app.use instead wherever you can. See also tf.about.volumes . : tf.fabric.Fabric python TF.isLoaded(features=None) : Show information about loaded features : tf.core.api.Api.isLoaded python TF.explore(show=True) : Get features by category, loaded or unloaded : tf.fabric.Fabric.explore python TF.loadAll(silent=\"auto\") : Load all loadable features. : tf.fabric.Fabric.loadAll python TF.load(features, add=False) : Load a bunch of features from scratch or additionally. : tf.fabric.Fabric.load python TF.ensureLoaded(features) : Make sure that features are loaded. : tf.core.api.Api.ensureLoaded python TF.makeAvailableIn(globals( : Make the members of the core API available in the global scope : tf.core.api.Api.makeAvailableIn python TF.ignored : Which features have been overridden. : tf.core.api.Api.ignored python TF.footprint() : Show memory footprint per feature : tf.core.api.Api.footprint - Volumes See also tf.about.volumes . python TF.getVolumes() : list all volumes of this dataset : tf.fabric.Fabric.getVolumes python TF.extract(volumes, .) : export volumes based on a volume specification : tf.fabric.Fabric.extract python TF.collect(volumes, .) : collect several volumes into a new collection : tf.advanced.display.export : tf.fabric.Fabric.collect Saving and Publishing python TF.save(nodeFeatures={}, edgeFeatures={}, metaData={} .) : Save a bunch of newly generated features to disk. : tf.fabric.Fabric.save python A.publishRelease(increase, message=None, description=None .) : Commit the dataset repo, tag it, release it, and attach the complete zipped data to it. : tf.advanced.repo.publishRelease - House keeping python TF.version : version number of TF. : tf.fabric.Fabric.version python TF.clearCache() : clears the cache of compiled TF data : tf.fabric.Fabric.clearCache python from tf.clean import clean python clean() : clears the cache of compiled TF data : tf.clean - Volume support TF datasets per volume or collection of a work. See also tf.about.volumes . python from tf.volumes import getVolumes getVolumes(volumeDir) : List volumes in a directory. : tf.volumes.extract.getVolumes python from tf.volumes import extract extract(work, volumes, .) : Extracts volumes from a work : tf.volumes.extract python from tf.volumes import collect collect(volumes, work, .) : Collects several volumes into a new collection : tf.volumes.collect - Dataset Operations python from tf.dataset import modify modify(source, target, .) : Modifies a TF dataset into a new TF dataset : tf.dataset.modify python from tf.dataset import Versions Versions(api, va, vb, slotMap) : Extends a slot mapping between versions of a TF dataset to a complete node mapping : tf.dataset.nodemaps - Data Interchange Custom node sets for search python from tf.lib import readSets from tf.lib import writeSets python readSets(sourceFile) : reads a named sets from file : tf.lib.readSets python writeSets(sets, destFile) : writes a named sets to file : tf.lib.writeSets - Export to Excel python A.export(results, .) : export formatted data : tf.advanced.display.export - Export to ZIP python A.zipAll() : store the complete corpus data in a file complete.zip : tf.advanced.zipdata.zipAll - Interchange with external annotation tools python from tf.convert.addnlp import NLPipeline python NLPipeline() : generate plain text, feed into NLP, ingest results : tf.convert.addnlp - python from convert.recorder import Recorder python Recorder() : generate annotatable plain text and import annotations : tf.convert.recorder - XML / TEI import python from tf.convert.xml import XML python X = XML( .) : convert XML source to full-fledged TF dataset plus app but no docs; put in your own conversion code, if you wish; see [Greek New Testament](https: nbviewer.org/github/ETCBC/nestle1904/blob/master/programs/tfFromLowfat.ipynb) : tf.convert.xml python from tf.convert.tei import TEI python T = TEI( .) : convert TEI source to full-fledged TF dataset plus app plus docs : tf.convert.tei - WATM export python from tf.app import use from tf.convert.watm import WATM python A = use( .) WA = WATM(A, ns, .) WA.makeText() WA.makeAnno() WA.writeAll() WA.testAll() : convert TF dataset to text tokens and annotations in JSON format, for consumption by TextRepo/AnnoRepo of [KNAW/HuC Digital Infrastructure](https: di.huc.knaw.nl/text-analysis-en.html). See [Mondriaan Proeftuin](https: github.com/annotation/mondriaan) [Suriano Letters](https: gitlab.huc.knaw.nl/suriano/letters) [TransLatin Corpus](https: gitlab.huc.knaw.nl/translatin/corpus) : tf.convert.watm python from tf.convert.watm import WATMS python W = WATM(org, repo, backend, ns, .) W.produce() : convert series of TF datasets to WATM : tf.convert.watm.WATMS - NLP import in order to use this, install Spacy, see tf.tools.myspacy python from tf.convert.addnlp import addTokensAndSentences python newVersion = addTokensAndSenteces(A) : add NLP output from Spacy to an existing TF dataset. See the docs how this is broken down in separate steps. : tf.convert.addnlp - pandas export python A.exportPandas() : export dataset as pandas data frame : tf.convert.pandas - MQL interchange python TF.exportMQL(mqlDb, exportDir=None) A.exportMQL(mqlDb, exportDir=None) : export loaded dataset to MQL : tf.convert.mql.exportMQL python from tf.convert.mql import importMQL TF = importMQL(mqlFile, saveDir) : convert MQL file to TF dataset : tf.convert.mql.importMQL - Walker conversion python from tf.convert.walker import CV python cv = CV(TF) : convert structured data to TF dataset : tf.convert.walker - Exploding python from tf.convert.tf import explode python explode(inLocation, outLocation) : explode TF feature files to straight data files without optimizations : tf.convert.tf.explode - TF App development python A.reuse() : reload configuration data : tf.advanced.app.App.reuse python from tf.advanced.find import loadModule python mmm = loadModule(\"mmm\", args) : load specific module supporting the corpus app : tf.advanced.find.loadModule ~/mypath/myname/app/config.yaml : settings for a TF App : tf.advanced.settings - Layered search (these work on the command-line if TF is installed) sh tf-make {dataset} {client} ship : generate a static site with a search interface in client-side JavaScript and publish it to GitHub pages. If {client} is left out, generate all clients that are defined for this dataset. Clients are defined in the app-{dataset} repo, under layeredsearch . More commands [here](https: github.com/annotation/text-fabric/blob/master/tf/client/make/help.py). : tf.client.make.build sh tf-make {dataset} serve : serve the search interfaces defined for {dataset} locally. More commands [here](https: github.com/annotation/text-fabric/blob/master/tf/client/make/help.py). - Annotation tools (these work in the TF browser and in Jupyter Notebooks) Named Entity Annotation sh tf {org}/{repo} tool=ner : Starts the TF browser for the corpus in org / repo and opens the manual annotation tool. : tf.about.annotateBrowser python NE = A.makeNer() : Sets up the 'manual' annotation API for the corpus in A . : tf.browser.ner.ner : More info and examples in tf.about.annotate . - Command-line tools (these work on the command-line if TF is installed) sh tf {org}/{repo} tf {org}/{repo} : Starts the TF browser for the corpus in org / repo . : tf.browser.start sh tf-zipall : Zips the TF dataset located by the current directory, with all its additional data modules , but only the latest version , so that it can be attached to a release on GitHub / GitLab. : tf.advanced.zipdata.zipAll and tf.zip sh tf-zip {org}/{repo} : Zips the TF dataset in org / repo so that it can be attached to a release on GitHub / GitLab. : tf.advanced.zipdata sh tf-nbconvert {inDirectory} {outDirectory} : Converts notebooks in inDirectory to HTML and stores them in outDirectory . : tf.tools.nbconvert sh tf-xmlschema analysis {schema}.xsd : Analyses an XML schema file and extracts meaningful information for processing the XML that adheres to that schema. : tf.tools.xmlschema sh tf-fromxml : When run in a repo it finds an XML source and converts it to TF. The resulting TF data is delivered in the repo. There is a hook to put your own conversion code in. : tf.convert.xml sh tf-fromtei : When run in a repo it finds a TEI source and converts it to TF. The resulting TF data is delivered in the repo. : tf.convert.tei sh tf-addnlp : When run in the repo of a TF dataset, it adds NLP output to it after running Spacy to get them. : tf.convert.addnlp " +"doc":" A. Advanced API Initialization, configuration, meta data, and linking python A = use('org/repo') : start up and load a corpus from a repository and deliver its API. : See tf.about.usefunc python A.hoist(globals( : Make the API handles F , E , T , L etc available in the global scope. : tf.advanced.app.App.load python A.load(features) : Load an extra bunch of features. : tf.advanced.app.App.load python A.featureTypes(show=True) : show for which types each feature is defined : tf.advanced.app.App.featureTypes python A.showContext( .) : show app settings : tf.advanced.settings.showContext python A.header(allMeta=False) : show colophon : tf.advanced.links.header python A.showProvenance( .) : show provenance of code and data : tf.advanced.links.showProvenance python A.webLink(n, .) : hyperlink to node n on the web : tf.advanced.links.webLink python A.flexLink(\"pages\") A.flexLink(\"tut\") : hyperlink to app tutorial and documentation : tf.advanced.links.flexLink python A.isLoaded(features=None) : Show information about loaded features : tf.core.api.Api.isLoaded python A.footprint() : Show memory footprint per feature : tf.core.api.Api.footprint - Displaying python A.specialCharacters() : show all hard-to-type characters in the corpus in a widget : tf.advanced.text.specialCharacters python A.showFormats() : show all text formats and their definitions : tf.advanced.text.showFormats python A.dm(markdownString) : display markdown string in notebook : tf.advanced.helpers.dm python A.dh(htmlString) : display HTML string in notebook : tf.advanced.helpers.dh python A.method(option1=value1, option2=value2, .) : Many of the following methods accept these options as keyword arguments: : tf.advanced.options python A.displayShow( .) : show display options : tf.advanced.display.displayShow python A.displayReset( .) : reset display options : tf.advanced.display.displayReset python A.displaySetup( .) : set up display options : tf.advanced.display.displaySetup python A.table(results, .) : plain rendering of tuple of tuples of node : tf.advanced.display.table python A.plainTuple(tup, .) : plain rendering of tuple of node : tf.advanced.display.plainTuple python A.plain(node, .) : plain rendering of node : tf.advanced.display.plain python A.show(results, .) : pretty rendering of tuple of tuples of node : tf.advanced.display.show python A.prettyTuple(tup, .) : pretty rendering of tuple of node : tf.advanced.display.prettyTuple python A.pretty(node, .) : pretty rendering of node : tf.advanced.display.pretty python A.unravel(node, .) : convert a graph to a tree : tf.advanced.unravel.unravel python A.getCss() : get the complete CSS style sheet for this app : tf.advanced.display.getCss - Search (high level) python A.search( .) : search, collect and deliver results, report number of results : tf.advanced.search.search - Sections and Structure python A.nodeFromSectionStr( .) : lookup node for section heading : tf.advanced.sections.nodeFromSectionStr python A.sectionStrFromNode( .) : lookup section heading for node : tf.advanced.sections.sectionStrFromNode python A.structureStrFromNode( .) : lookup structure heading for node : tf.advanced.sections.structureStrFromNode - Volumes and collections See also tf.about.volumes . python A.getVolumes() : list all volumes of this dataset : tf.fabric.Fabric.getVolumes python A.extract(volumes, .) : export volumes based on a volume specification : tf.fabric.Fabric.extract python A.collect(volumes, .) : collect several volumes into a new collection : tf.advanced.display.export : tf.fabric.Fabric.collect - Export to Excel python A.export(results, .) : export formatted data : tf.advanced.display.export - Logging python A.dm(markdownString) : display markdown string in notebook : tf.advanced.helpers.dm python A.dh(htmlString) : display HTML string in notebook : tf.advanced.helpers.dh python A.version : version number of data of the corpus. : tf.fabric.Fabric.version The following methods work also for TF. instead of A. : python A.banner : banner of the TF program. : tf.fabric.Fabric.banner python A.isSilent() : report the verbosity of TF : tf.core.timestamp.Timestamp.isSilent python A.silentOn(deep=False) : make TF (deeply) silent from now on. : tf.core.timestamp.Timestamp.silentOn python A.silentOff() : make TF talkative from now on. : tf.core.timestamp.Timestamp.silentOff python A.setSilent(silent) : set the verbosity of TF. : tf.core.timestamp.Timestamp.setSilent python A.indent(level=None, reset=False) : Sets up indentation and timing of following messages : tf.core.timestamp.Timestamp.indent python A.info(msg, tm=True, nl=True, .) : informational message : tf.core.timestamp.Timestamp.info python A.warning(msg, tm=True, nl=True, .) : warning message : tf.core.timestamp.Timestamp.warning python A.error(msg, tm=True, nl=True, .) : error message : tf.core.timestamp.Timestamp.error - N. F. E. L. T. S. C. Core API N. Nodes Read about the canonical ordering here: tf.core.nodes . python N.walk() : generator of all nodes in canonical ordering : tf.core.nodes.Nodes.walk python N.sortNodes(nodes) : sorts nodes in the canonical ordering : tf.core.nodes.Nodes.sortNodes python N.otypeRank[nodeType] : ranking position of nodeType : tf.core.nodes.Nodes.otypeRank python N.sortKey(node) : defines the canonical ordering on nodes : tf.core.nodes.Nodes.sortKey python N.sortKeyTuple(tup) : extends the canonical ordering on nodes to tuples of nodes : tf.core.nodes.Nodes.sortKeyTuple python N.sortKeyChunk(node) : defines the canonical ordering on node chunks : tf.core.nodes.Nodes.sortKeyChunk - F. Node features python Fall() : all loaded feature names (node features only) : tf.core.api.Api.Fall python F.fff.v(node) : get value of node feature fff : tf.core.nodefeature.NodeFeature.v python F.fff.s(value) : get nodes where feature fff has value : tf.core.nodefeature.NodeFeature.s python F.fff.freqList( .) : frequency list of values of fff : tf.core.nodefeature.NodeFeature.freqList python F.fff.items( .) : generator of all entries of fff as mapping from nodes to values : tf.core.nodefeature.NodeFeature.items python F.fff.meta : meta data of feature fff : tf.core.nodefeature.NodeFeature.meta python Fs('fff') : identical to F.ffff , usable if name of feature is variable : tf.core.api.Api.Fs - Special node feature otype Maps nodes to their types. python F.otype.v(node) : get type of node : tf.core.otypefeature.OtypeFeature.v python F.otype.s(nodeType) : get all nodes of type nodeType : tf.core.otypefeature.OtypeFeature.s python F.otype.sInterval(nodeType) : gives start and ending nodes of nodeType : tf.core.otypefeature.OtypeFeature.sInterval python F.otype.items( .) : generator of all (node, type) pairs. : tf.core.otypefeature.OtypeFeature.items python F.otype.meta : meta data of feature otype : tf.core.otypefeature.OtypeFeature.meta python F.otype.maxSlot : the last slot node : tf.core.otypefeature.OtypeFeature.maxSlot python F.otype.maxNode : the last node : tf.core.otypefeature.OtypeFeature.maxNode python F.otype.slotType : the slot type : tf.core.otypefeature.OtypeFeature.slotType python F.otype.all : sorted list of all node types : tf.core.otypefeature.OtypeFeature.all - E. Edge features python Eall() : all loaded feature names (edge features only) : tf.core.api.Api.Eall python E.fff.f(node) : get value of feature fff for edges from node : tf.core.edgefeature.EdgeFeature.f python E.fff.t(node) : get value of feature fff for edges to node : tf.core.edgefeature.EdgeFeature.t python E.fff.freqList( .) : frequency list of values of fff : tf.core.edgefeature.EdgeFeature.freqList python E.fff.items( .) : generator of all entries of fff as mapping from edges to values : tf.core.edgefeature.EdgeFeature.items python E.fff.b(node) : get value of feature fff for edges from and to node : tf.core.edgefeature.EdgeFeature.b python E.fff.meta : all meta data of feature fff : tf.core.edgefeature.EdgeFeature.meta python Es('fff') : identical to E.fff , usable if name of feature is variable : tf.core.api.Api.Es - Special edge feature oslots Maps nodes to the set of slots they occupy. python E.oslots.items( .) : generator of all entries of oslots as mapping from nodes to sets of slots : tf.core.oslotsfeature.OslotsFeature.items python E.oslots.s(node) : set of slots linked to node : tf.core.oslotsfeature.OslotsFeature.s python E.oslots.meta : all meta data of feature oslots : tf.core.oslotsfeature.OslotsFeature.meta - L. Locality python L.i(node, otype= .) : go to intersecting nodes : tf.core.locality.Locality.i python L.u(node, otype= .) : go one level up : tf.core.locality.Locality.u python L.d(node, otype= .) : go one level down : tf.core.locality.Locality.d python L.p(node, otype= .) : go to adjacent previous nodes : tf.core.locality.Locality.p python L.n(node, otype= .) : go to adjacent next nodes : tf.core.locality.Locality.n - T. Text python T.text(node, fmt= ., .) : give formatted text associated with node : tf.core.text.Text.text - Sections Rigid 1 or 2 or 3 sectioning system python T.sectionTuple(node) : give tuple of section nodes that contain node : tf.core.text.Text.sectionTuple python T.sectionFromNode(node) : give section heading of node : tf.core.text.Text.sectionFromNode python T.nodeFromSection(section) : give node for section heading : tf.core.text.Text.nodeFromSection - Structure Flexible multilevel sectioning system python T.headingFromNode(node) : give structure heading of node : tf.core.text.Text.headingFromNode python T.nodeFromHeading(heading) : give node for structure heading : tf.core.text.Text.nodeFromHeading python T.structureInfo() : give summary of dataset structure : tf.core.text.Text.structureInfo python T.structure(node) : give structure of node and all in it. : tf.core.text.Text.structure python T.structurePretty(node) : pretty print structure of node and all in it. : tf.core.text.Text.structurePretty python T.top() : give all top-level structural nodes in the dataset : tf.core.text.Text.top python T.up(node) : gives parent of structural node : tf.core.text.Text.up python T.down(node) : gives children of structural node : tf.core.text.Text.down - S. Search (low level) [ searchRough ](https: nbviewer.jupyter.org/github/ETCBC/bhsa/blob/master/tutorial/searchRough.ipynb) Preparation python S.search(query, limit=None) : Query the TF dataset with a template : tf.search.search.Search.search python S.study(query, .) : Study the query in order to set up a plan : tf.search.search.Search.study python S.showPlan(details=False) : Show the search plan resulting from the last study. : tf.search.search.Search.showPlan python S.relationsLegend() : Catalog of all relational devices in search templates : tf.search.search.Search.relationsLegend - Fetching results python S.count(progress=None, limit=None) : Count the results, up to a limit : tf.search.search.Search.count python S.fetch(limit=None, .) : Fetches the results, up to a limit : tf.search.search.Search.fetch python S.glean(tup) : Renders a single result into something human readable. : tf.search.search.Search.glean - Implementation python S.tweakPerformance( .) : Set certain parameters that influence the performance of search. : tf.search.search.Search.tweakPerformance - C. Computed data components. Access to pre-computed data: tf.core.computed.Computeds . All components have just one useful attribute: .data . python Call() : all pre-computed data component names : tf.core.api.Api.Call python Cs('ccc') : identical to C.ccc , usable if name of component is variable : tf.core.api.Api.Cs python C.levels.data : various statistics on node types : tf.core.prepare.levels python C.order.data : the canonical order of the nodes ( tf.core.nodes ) : tf.core.prepare.order python C.rank.data : the rank of the nodes in the canonical order ( tf.core.nodes ) : tf.core.prepare.rank python C.levUp.data : feeds the tf.core.locality.Locality.u function : tf.core.prepare.levUp python C.levDown.data : feeds the tf.core.locality.Locality.d function : tf.core.prepare.levDown python C.boundary.data : feeds the tf.core.locality.Locality.p and tf.core.locality.Locality.n functions : tf.core.prepare.boundary python C.characters.data : frequency list of characters in a corpus, separately for all the text formats : tf.core.prepare.characters python C.sections.data : feeds the section part of tf.core.text : tf.core.prepare.sections python C.structure.data : feeds the structure part of tf.core.text : tf.core.prepare.structure - TF. Dataset Loading python TF = Fabric(locations=dirs, modules=subdirs, volume=None, collection=None, silent=\"auto\") : Initialize API on work or single volume or collection of a work from explicit directories. Use tf.app.use instead wherever you can. See also tf.about.volumes . : tf.fabric.Fabric python TF.isLoaded(features=None) : Show information about loaded features : tf.core.api.Api.isLoaded python TF.explore(show=True) : Get features by category, loaded or unloaded : tf.fabric.Fabric.explore python TF.loadAll(silent=\"auto\") : Load all loadable features. : tf.fabric.Fabric.loadAll python TF.load(features, add=False) : Load a bunch of features from scratch or additionally. : tf.fabric.Fabric.load python TF.ensureLoaded(features) : Make sure that features are loaded. : tf.core.api.Api.ensureLoaded python TF.makeAvailableIn(globals( : Make the members of the core API available in the global scope : tf.core.api.Api.makeAvailableIn python TF.ignored : Which features have been overridden. : tf.core.api.Api.ignored python TF.footprint() : Show memory footprint per feature : tf.core.api.Api.footprint - Volumes See also tf.about.volumes . python TF.getVolumes() : list all volumes of this dataset : tf.fabric.Fabric.getVolumes python TF.extract(volumes, .) : export volumes based on a volume specification : tf.fabric.Fabric.extract python TF.collect(volumes, .) : collect several volumes into a new collection : tf.advanced.display.export : tf.fabric.Fabric.collect Saving and Publishing python TF.save(nodeFeatures={}, edgeFeatures={}, metaData={} .) : Save a bunch of newly generated features to disk. : tf.fabric.Fabric.save python A.publishRelease(increase, message=None, description=None .) : Commit the dataset repo, tag it, release it, and attach the complete zipped data to it. : tf.advanced.repo.publishRelease - House keeping python TF.version : version number of TF. : tf.fabric.Fabric.version python TF.clearCache() : clears the cache of compiled TF data : tf.fabric.Fabric.clearCache python from tf.clean import clean python clean() : clears the cache of compiled TF data : tf.clean - Volume support TF datasets per volume or collection of a work. See also tf.about.volumes . python from tf.volumes import getVolumes getVolumes(volumeDir) : List volumes in a directory. : tf.volumes.extract.getVolumes python from tf.volumes import extract extract(work, volumes, .) : Extracts volumes from a work : tf.volumes.extract python from tf.volumes import collect collect(volumes, work, .) : Collects several volumes into a new collection : tf.volumes.collect - Dataset Operations python from tf.dataset import modify modify(source, target, .) : Modifies a TF dataset into a new TF dataset : tf.dataset.modify python from tf.dataset import Versions Versions(api, va, vb, slotMap) : Extends a slot mapping between versions of a TF dataset to a complete node mapping : tf.dataset.nodemaps - Data Interchange Custom node sets for search python from tf.lib import readSets from tf.lib import writeSets python readSets(sourceFile) : reads a named sets from file : tf.lib.readSets python writeSets(sets, destFile) : writes a named sets to file : tf.lib.writeSets - Export to Excel python A.export(results, .) : export formatted data : tf.advanced.display.export - Export to ZIP python A.zipAll() : store the complete corpus data in a file complete.zip : tf.advanced.zipdata.zipAll - Interchange with external annotation tools python from tf.convert.addnlp import NLPipeline python NLPipeline() : generate plain text, feed into NLP, ingest results : tf.convert.addnlp - python from convert.recorder import Recorder python Recorder() : generate annotatable plain text and import annotations : tf.convert.recorder - XML / TEI import python from tf.convert.xml import XML python X = XML( .) : convert XML source to full-fledged TF dataset plus app but no docs; put in your own conversion code, if you wish; see [Greek New Testament](https: nbviewer.org/github/ETCBC/nestle1904/blob/master/programs/tfFromLowfat.ipynb) : tf.convert.xml python from tf.convert.tei import TEI python T = TEI( .) : convert TEI source to full-fledged TF dataset plus app plus docs : tf.convert.tei - WATM export python from tf.app import use from tf.convert.watm import WATM python A = use( .) WA = WATM(A, ns, .) WA.makeText() WA.makeAnno() WA.writeAll() WA.testAll() : convert TF dataset to text tokens and annotations in JSON format, for consumption by TextRepo/AnnoRepo of [KNAW/HuC Digital Infrastructure](https: di.huc.knaw.nl/text-analysis-en.html). See [Mondriaan Proeftuin](https: github.com/annotation/mondriaan) [Suriano Letters](https: gitlab.huc.knaw.nl/suriano/letters) [TransLatin Corpus](https: gitlab.huc.knaw.nl/translatin/corpus) : tf.convert.watm python from tf.convert.watm import WATMS python W = WATM(org, repo, backend, ns, .) W.produce() : convert series of TF datasets to WATM : tf.convert.watm.WATMS - NLP import in order to use this, install Spacy, see tf.tools.myspacy python from tf.convert.addnlp import addTokensAndSentences python newVersion = addTokensAndSenteces(A) : add NLP output from Spacy to an existing TF dataset. See the docs how this is broken down in separate steps. : tf.convert.addnlp - pandas export python A.exportPandas() : export dataset as pandas data frame : tf.convert.pandas - MQL interchange python TF.exportMQL(mqlDb, exportDir=None) A.exportMQL(mqlDb, exportDir=None) : export loaded dataset to MQL : tf.convert.mql.exportMQL python from tf.convert.mql import importMQL TF = importMQL(mqlFile, saveDir) : convert MQL file to TF dataset : tf.convert.mql.importMQL - Walker conversion python from tf.convert.walker import CV python cv = CV(TF) : convert structured data to TF dataset : tf.convert.walker - Exploding python from tf.convert.tf import explode python explode(inLocation, outLocation) : explode TF feature files to straight data files without optimizations : tf.convert.tf.explode - TF App development python A.reuse() : reload configuration data : tf.advanced.app.App.reuse python from tf.advanced.find import loadModule python mmm = loadModule(\"mmm\", args) : load specific module supporting the corpus app : tf.advanced.find.loadModule ~/mypath/myname/app/config.yaml : settings for a TF App : tf.advanced.settings - Layered search (these work on the command-line if TF is installed) sh tf-make {dataset} {client} ship : generate a static site with a search interface in client-side JavaScript and publish it to GitHub pages. If {client} is left out, generate all clients that are defined for this dataset. Clients are defined in the app-{dataset} repo, under layeredsearch . More commands [here](https: github.com/annotation/text-fabric/blob/master/tf/client/make/help.py). : tf.client.make.build sh tf-make {dataset} serve : serve the search interfaces defined for {dataset} locally. More commands [here](https: github.com/annotation/text-fabric/blob/master/tf/client/make/help.py). - Annotation tools (these work in the TF browser and in Jupyter Notebooks) Named Entity Annotation sh tf {org}/{repo} tool=ner : Starts the TF browser for the corpus in org / repo and opens the manual annotation tool. : tf.about.annotateBrowser python NE = A.makeNer() : Sets up the 'manual' annotation API for the corpus in A . : tf.browser.ner.ner : More info and examples in tf.about.annotate . - Command-line tools (these work on the command-line if TF is installed) sh tf {org}/{repo} tf {org}/{repo} : Starts the TF browser for the corpus in org / repo . : tf.browser.start sh tf-zipall : Zips the TF dataset located by the current directory, with all its additional data modules , but only the latest version , so that it can be attached to a release on GitHub / GitLab. : tf.advanced.zipdata.zipAll and tf.zip sh tf-zip {org}/{repo} : Zips the TF dataset in org / repo so that it can be attached to a release on GitHub / GitLab. : tf.advanced.zipdata sh tf-nbconvert {inDirectory} {outDirectory} : Converts notebooks in inDirectory to HTML and stores them in outDirectory . : tf.tools.nbconvert sh tf-xmlschema analysis {schema}.xsd : Analyses an XML schema file and extracts meaningful information for processing the XML that adheres to that schema. : tf.tools.xmlschema sh tf-fromxml : When run in a repo it finds an XML source and converts it to TF. The resulting TF data is delivered in the repo. There is a hook to put your own conversion code in. : tf.convert.xml sh tf-fromtei : When run in a repo it finds a TEI source and converts it to TF. The resulting TF data is delivered in the repo. : tf.convert.tei sh tf-addnlp : When run in the repo of a TF dataset, it adds NLP output to it after running Spacy to get them. : tf.convert.addnlp " }, { "ref":"tf.volumes", @@ -6586,6 +6624,12 @@ INDEX=[ "func":1 }, { +"ref":"tf.convert.app.app.TfApp.featureTypes", +"url":16, +"doc":"For which node types is each feature defined? It computes on the fly for each feature the node types for which the feature has defined values. Parameters show: boolean, optional True Whether to output the result in pretty markdown. Returns - dict If show is true, None is returned, but if show is false, a dict is returned, keyed by features and the value for each feature is the list of types for which it has defined values.", +"func":1 +}, +{ "ref":"tf.convert.app.app.TfApp.context", "url":16, "doc":"Result of interpreting all configuration options in config.yaml ." diff --git a/tf/about/annotate.html b/tf/about/annotate.html index ff95bc9f2..f28562c21 100644 --- a/tf/about/annotate.html +++ b/tf/about/annotate.html @@ -298,7 +298,7 @@
Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/annotate.md
diff --git a/tf/about/annotateBrowser.html b/tf/about/annotateBrowser.html
index 43ad8ae82..eec0d597a 100644
--- a/tf/about/annotateBrowser.html
+++ b/tf/about/annotateBrowser.html
@@ -267,7 +267,7 @@ 

Programming

Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/annotateBrowser.md
diff --git a/tf/about/apps.html b/tf/about/apps.html
index 509f4025d..407e7ff52 100644
--- a/tf/about/apps.html
+++ b/tf/about/apps.html
@@ -115,7 +115,7 @@ 

Two contexts

Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/apps.md
diff --git a/tf/about/background.html b/tf/about/background.html
index 366259aaa..e2a524172 100644
--- a/tf/about/background.html
+++ b/tf/about/background.html
@@ -155,7 +155,7 @@ 

History

Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/background.md
diff --git a/tf/about/browser.html b/tf/about/browser.html
index dad9e2edf..4ed23c43f 100644
--- a/tf/about/browser.html
+++ b/tf/about/browser.html
@@ -174,7 +174,7 @@ 

UNICODE in Excel CSVs

Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/browser.md
diff --git a/tf/about/clientmanual.html b/tf/about/clientmanual.html
index ff665d93d..500256553 100644
--- a/tf/about/clientmanual.html
+++ b/tf/about/clientmanual.html
@@ -565,7 +565,7 @@ 

Credits

Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/clientmanual.md
diff --git a/tf/about/code.html b/tf/about/code.html
index a4e0f00d5..4873a5189 100644
--- a/tf/about/code.html
+++ b/tf/about/code.html
@@ -98,7 +98,7 @@ 

Writing

Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/code.md
diff --git a/tf/about/corpora.html b/tf/about/corpora.html
index 9ab95dd2f..d18d034e6 100644
--- a/tf/about/corpora.html
+++ b/tf/about/corpora.html
@@ -351,7 +351,7 @@ 

Extra data

Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/corpora.md
diff --git a/tf/about/datamodel.html b/tf/about/datamodel.html
index fa4b85bb7..fefde1c49 100644
--- a/tf/about/datamodel.html
+++ b/tf/about/datamodel.html
@@ -265,7 +265,7 @@ 

Serializing and pre-computing

Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/datamodel.md
diff --git a/tf/about/datasharing.html b/tf/about/datasharing.html
index 49004bb00..f16c91763 100644
--- a/tf/about/datasharing.html
+++ b/tf/about/datasharing.html
@@ -362,7 +362,7 @@ 

More modules at the same time

Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/datasharing.md
diff --git a/tf/about/displaydesign.html b/tf/about/displaydesign.html
index b2a55f270..aa7091185 100644
--- a/tf/about/displaydesign.html
+++ b/tf/about/displaydesign.html
@@ -151,7 +151,7 @@ 

Output

Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/displaydesign.md
diff --git a/tf/about/faq.html b/tf/about/faq.html
index 7c4e0ccce..3bd6efb3f 100644
--- a/tf/about/faq.html
+++ b/tf/about/faq.html
@@ -161,7 +161,7 @@ 

GitHub Rate Limit Exceeded!

Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/faq.md
diff --git a/tf/about/fileformats.html b/tf/about/fileformats.html
index 6ddd133b8..71ca6fe33 100644
--- a/tf/about/fileformats.html
+++ b/tf/about/fileformats.html
@@ -158,7 +158,7 @@ 

Single values

Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/fileformats.md
diff --git a/tf/about/index.html b/tf/about/index.html
index 3670197b8..f26fea21d 100644
--- a/tf/about/index.html
+++ b/tf/about/index.html
@@ -33,7 +33,7 @@ 

Documents

Expand source code -Browse git +Browse git
"""
 # Documents
diff --git a/tf/about/install.html b/tf/about/install.html
index 758a43bd7..d92715c54 100644
--- a/tf/about/install.html
+++ b/tf/about/install.html
@@ -108,7 +108,7 @@ 

Note for Linux users

Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/install.md
diff --git a/tf/about/manual.html b/tf/about/manual.html
index 85f2cb13a..376267921 100644
--- a/tf/about/manual.html
+++ b/tf/about/manual.html
@@ -390,7 +390,7 @@ 

Keyboard shortcuts

Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/manual.md
diff --git a/tf/about/optimizations.html b/tf/about/optimizations.html
index b3861f417..4a80a631b 100644
--- a/tf/about/optimizations.html
+++ b/tf/about/optimizations.html
@@ -187,7 +187,7 @@ 

Edge features

Expand source code -Browse git +Browse git
"""
 .. include:: ../docs/about/optimizations.md
diff --git a/tf/about/releases.html b/tf/about/releases.html
index 89632fbd9..8d6d0f747 100644
--- a/tf/about/releases.html
+++ b/tf/about/releases.html
@@ -43,6 +43,20 @@ 

Release notes

12

12.5

+

12.5.2

+

2024-06-13

+
    +
  • +

    New function to show the types for which each feature has defined values. +Thanks to Marek Polášek for asking for it, writing an algorithm to produce this +information, and then speeding it up 10-fold! For details see this +cookbook

    +
  • +
  • +

    Working on integrating NER by spreadsheet in the TF browser. This is currently in +an unfinished state.

    +
  • +

12.5.1

2024-06-06

    @@ -486,7 +500,7 @@

    Older releases

    Expand source code -Browse git +Browse git
    """
     .. include:: ../docs/about/releases.md
    @@ -560,6 +574,7 @@ 

    Index

  • Release notes
    • 12
      • 12.5 diff --git a/tf/about/releasesold.html b/tf/about/releasesold.html index 43bdea740..aaec95b55 100644 --- a/tf/about/releasesold.html +++ b/tf/about/releasesold.html @@ -3430,7 +3430,7 @@
        Changed
        Expand source code -Browse git +Browse git
        """
         .. include:: ../docs/about/releasesold.md
        diff --git a/tf/about/searchdesign.html b/tf/about/searchdesign.html
        index 467f21017..9b0ba3906 100644
        --- a/tf/about/searchdesign.html
        +++ b/tf/about/searchdesign.html
        @@ -477,7 +477,7 @@ 

        Small-first strategy

        Expand source code -Browse git +Browse git
        """
         .. include:: ../docs/about/searchdesign.md
        diff --git a/tf/about/searchusage.html b/tf/about/searchusage.html
        index 018aa27b8..004f51a26 100644
        --- a/tf/about/searchusage.html
        +++ b/tf/about/searchusage.html
        @@ -776,7 +776,7 @@ 
        Implementation
        Expand source code -Browse git +Browse git
        """
         .. include:: ../docs/about/searchusage.md
        diff --git a/tf/about/tests.html b/tf/about/tests.html
        index 0a451dddf..535966ad0 100644
        --- a/tf/about/tests.html
        +++ b/tf/about/tests.html
        @@ -71,7 +71,7 @@ 

        Relations

        Expand source code -Browse git +Browse git
        """
         .. include:: ../docs/about/tests.md
        diff --git a/tf/about/use.html b/tf/about/use.html
        index 994dff8d2..230b9fecb 100644
        --- a/tf/about/use.html
        +++ b/tf/about/use.html
        @@ -90,7 +90,7 @@ 

        TF API

        Expand source code -Browse git +Browse git
        """
         .. include:: ../docs/about/use.md
        diff --git a/tf/about/usefunc.html b/tf/about/usefunc.html
        index 6920112b6..d739f268d 100644
        --- a/tf/about/usefunc.html
        +++ b/tf/about/usefunc.html
        @@ -419,7 +419,7 @@ 

        Prevent data loading

        Expand source code -Browse git +Browse git
        """
         .. include:: ../docs/about/usefunc.md
        diff --git a/tf/about/variants.html b/tf/about/variants.html
        index 89268be5f..15b284cd3 100644
        --- a/tf/about/variants.html
        +++ b/tf/about/variants.html
        @@ -438,7 +438,7 @@ 

        The stack

        Expand source code -Browse git +Browse git
        """
         .. include:: ../docs/about/variants.md
        diff --git a/tf/about/volumes.html b/tf/about/volumes.html
        index fffb9a67c..3e9795860 100644
        --- a/tf/about/volumes.html
        +++ b/tf/about/volumes.html
        @@ -323,7 +323,7 @@ 

        Reflection

        Expand source code -Browse git +Browse git
        """
         .. include:: ../docs/about/volumes.md
        diff --git a/tf/advanced/annotate.html b/tf/advanced/annotate.html
        index 9cc18c91d..b493c3e85 100644
        --- a/tf/advanced/annotate.html
        +++ b/tf/advanced/annotate.html
        @@ -34,7 +34,7 @@ 

        Module tf.advanced.annotate

        Expand source code -Browse git +Browse git
        """
         Enable manual annotation APIs.
        @@ -84,7 +84,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def annotateApi(app):
             """Produce the interchange functions API.
        @@ -106,7 +106,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def makeNer(app):
             return NER(app)
        diff --git a/tf/advanced/app.html b/tf/advanced/app.html index 2a134a204..81b0d54fa 100644 --- a/tf/advanced/app.html +++ b/tf/advanced/app.html @@ -31,12 +31,12 @@

        Module tf.advanced.app

        Expand source code -Browse git +Browse git
        import types
         import traceback
         
        -from ..parameters import ORG, RELATIVE, OMAP
        +from ..parameters import ORG, RELATIVE, OMAP, OTYPE
         from ..fabric import Fabric
         from ..lib import readSets
         from ..core.helpers import console, mergeDict
        @@ -417,6 +417,67 @@ 

        Module tf.advanced.app

        if hoist: api.makeAvailableIn(hoist) + def featureTypes(self, show=True): + """For which node types is each feature defined? + + It computes on the fly for each feature the node types for which + the feature has defined values. + + Parameters + ---------- + show: boolean, optional True + Whether to output the result in pretty markdown. + + Returns + ------- + dict + If `show` is true, None is returned, but if `show` is false, + a dict is returned, keyed by features and the value for each feature + is the list of types for which it has defined values. + """ + if hasattr(self, "featureTypeMap"): + info = self.featureTypeMap + else: + api = self.api + F = api.F + Fs = api.Fs + Fall = api.Fall + + nodesByType = {} + + allFeatures = [p for p in Fall() if p != OTYPE] + allTypes = F.otype.all + + for tp in allTypes: + nodesByType[tp] = set(F.otype.s(tp)) + + info = {} + + for feat in allFeatures: + featNodes = {i[0] for i in Fs(feat).items()} + + for tp in allTypes: + if len(featNodes & nodesByType[tp]) > 0: + info.setdefault(feat, []).append(tp) + + self.featureTypeMap = info + + if show: + md = [] + md.extend(["""feature | node types""", """:- | :-"""]) + + for feat, tps in sorted(info.items()): + tpsRep = "*" + "*, *".join(tps) + "*" + md.append(f"""**{feat}** | {tpsRep}""") + + self.dm("\n".join(md)) + self.dm( + "To get this overview in a dict, " + "call `A.featureTypes(show=False)`\n" + ) + else: + return info + def findApp( appName, @@ -834,7 +895,7 @@

        Parameters

        Expand source code -Browse git +Browse git
        def findApp(
             appName,
        @@ -1129,7 +1190,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def loadApp(silent=DEEP):
             """Loads a given TF app or loads the TF app based on the working directory.
        @@ -1197,7 +1258,7 @@ 

        See Also

        Expand source code -Browse git +Browse git
        def useApp(appName, backend):
             """Make use of a corpus.
        @@ -1299,7 +1360,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        class App:
             def __init__(
        @@ -1626,7 +1687,68 @@ 

        Parameters

        displayApi(self, silent=DEEP) textApi(self) if hoist: - api.makeAvailableIn(hoist)
        + api.makeAvailableIn(hoist) + + def featureTypes(self, show=True): + """For which node types is each feature defined? + + It computes on the fly for each feature the node types for which + the feature has defined values. + + Parameters + ---------- + show: boolean, optional True + Whether to output the result in pretty markdown. + + Returns + ------- + dict + If `show` is true, None is returned, but if `show` is false, + a dict is returned, keyed by features and the value for each feature + is the list of types for which it has defined values. + """ + if hasattr(self, "featureTypeMap"): + info = self.featureTypeMap + else: + api = self.api + F = api.F + Fs = api.Fs + Fall = api.Fall + + nodesByType = {} + + allFeatures = [p for p in Fall() if p != OTYPE] + allTypes = F.otype.all + + for tp in allTypes: + nodesByType[tp] = set(F.otype.s(tp)) + + info = {} + + for feat in allFeatures: + featNodes = {i[0] for i in Fs(feat).items()} + + for tp in allTypes: + if len(featNodes & nodesByType[tp]) > 0: + info.setdefault(feat, []).append(tp) + + self.featureTypeMap = info + + if show: + md = [] + md.extend(["""feature | node types""", """:- | :-"""]) + + for feat, tps in sorted(info.items()): + tpsRep = "*" + "*, *".join(tps) + "*" + md.append(f"""**{feat}** | {tpsRep}""") + + self.dm("\n".join(md)) + self.dm( + "To get this overview in a dict, " + "call `A.featureTypes(show=False)`\n" + ) + else: + return info

        Subclasses

          @@ -1641,6 +1763,92 @@

          Instance variables

          Methods

          +
          +def featureTypes(self, show=True) +
          +
          +

          For which node types is each feature defined?

          +

          It computes on the fly for each feature the node types for which +the feature has defined values.

          +

          Parameters

          +
          +
          show : boolean, optional True
          +
          Whether to output the result in pretty markdown.
          +
          +

          Returns

          +
          +
          dict
          +
          If show is true, None is returned, but if show is false, +a dict is returned, keyed by features and the value for each feature +is the list of types for which it has defined values.
          +
          +
          + +Expand source code +Browse git + +
          def featureTypes(self, show=True):
          +    """For which node types is each feature defined?
          +
          +    It computes on the fly for each feature the node types for which
          +    the feature has defined values.
          +
          +    Parameters
          +    ----------
          +    show: boolean, optional True
          +        Whether to output the result in pretty markdown.
          +
          +    Returns
          +    -------
          +    dict
          +        If `show` is true, None is returned, but if `show` is false,
          +        a dict is returned, keyed by features and the value for each feature
          +        is the list of types for which it has defined values.
          +    """
          +    if hasattr(self, "featureTypeMap"):
          +        info = self.featureTypeMap
          +    else:
          +        api = self.api
          +        F = api.F
          +        Fs = api.Fs
          +        Fall = api.Fall
          +
          +        nodesByType = {}
          +
          +        allFeatures = [p for p in Fall() if p != OTYPE]
          +        allTypes = F.otype.all
          +
          +        for tp in allTypes:
          +            nodesByType[tp] = set(F.otype.s(tp))
          +
          +        info = {}
          +
          +        for feat in allFeatures:
          +            featNodes = {i[0] for i in Fs(feat).items()}
          +
          +            for tp in allTypes:
          +                if len(featNodes & nodesByType[tp]) > 0:
          +                    info.setdefault(feat, []).append(tp)
          +
          +        self.featureTypeMap = info
          +
          +    if show:
          +        md = []
          +        md.extend(["""feature | node types""", """:- | :-"""])
          +
          +        for feat, tps in sorted(info.items()):
          +            tpsRep = "*" + "*, *".join(tps) + "*"
          +            md.append(f"""**{feat}** | {tpsRep}""")
          +
          +        self.dm("\n".join(md))
          +        self.dm(
          +            "To get this overview in a dict, "
          +            "call `A.featureTypes(show=False)`\n"
          +        )
          +    else:
          +        return info
          +
          +
          def hoist(self, hoist, silent=None)
          @@ -1665,7 +1873,7 @@

          Parameters

          Expand source code -Browse git +Browse git
          def hoist(self, hoist, silent=None):
               """Hoist the API handles of this TF app to the global scope.
          @@ -1733,7 +1941,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def load(self, features, silent=SILENT_D):
               """Loads extra features in addition to the main dataset.
          @@ -1771,7 +1979,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def reinit(self):
               """TF Apps may override this method.
          @@ -1806,7 +2014,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def reuse(self, hoist=False):
               """Re-initialize the app.
          @@ -1950,8 +2158,9 @@ 

          Index

          • App

            -
              +
              • context
              • +
              • featureTypes
              • hoist
              • load
              • reinit
              • diff --git a/tf/advanced/condense.html b/tf/advanced/condense.html index b1681fda5..ea00ab469 100644 --- a/tf/advanced/condense.html +++ b/tf/advanced/condense.html @@ -31,7 +31,7 @@

                Module tf.advanced.condense

                Expand source code -Browse git +Browse git
                def condense(api, tuples, condenseType, multiple=False):
                     F = api.F
                @@ -135,7 +135,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def condense(api, tuples, condenseType, multiple=False):
                     F = api.F
                @@ -192,7 +192,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def condenseSet(api, tup, condenseType):
                     F = api.F
                diff --git a/tf/advanced/data.html b/tf/advanced/data.html
                index 532fabb42..a56fbc07b 100644
                --- a/tf/advanced/data.html
                +++ b/tf/advanced/data.html
                @@ -31,7 +31,7 @@ 

                Module tf.advanced.data

                Expand source code -Browse git +Browse git
                from ..core.helpers import itemize
                 from ..core.files import backendRep, expandDir, prefixSlash, normpath
                @@ -496,7 +496,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def getModulesData(*args):
                     """Retrieve all data for a corpus.
                @@ -556,7 +556,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                class AppData:
                     def __init__(
                @@ -989,7 +989,7 @@ 

                See Also

                Expand source code -Browse git +Browse git
                def getExtra(self):
                     """Get the extra data specified by the settings of the corpus.
                @@ -1051,7 +1051,7 @@ 

                See Also

                Expand source code -Browse git +Browse git
                def getMain(self):
                     """Get the main data of the corpus.
                @@ -1126,7 +1126,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def getModule(
                     self,
                @@ -1271,7 +1271,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def getModules(self):
                     """Get data from additional local directories.
                @@ -1342,7 +1342,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def getRefs(self):
                     """Get data from additional modules.
                @@ -1397,7 +1397,7 @@ 

                See Also

                Expand source code -Browse git +Browse git
                def getStandard(self):
                     """Get the data of the standard modules specified by the settings of the corpus.
                diff --git a/tf/advanced/display.html b/tf/advanced/display.html
                index fb02d9b0e..c9ed13f11 100644
                --- a/tf/advanced/display.html
                +++ b/tf/advanced/display.html
                @@ -69,7 +69,7 @@ 

                See also

                Expand source code -Browse git +Browse git
                """
                 # Display
                @@ -1126,7 +1126,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def displayApi(app, silent=SILENT_D):
                     """Produce the display API.
                @@ -1193,7 +1193,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def displayReset(app, *options):
                     """Restore display parameters to their defaults.
                @@ -1251,7 +1251,7 @@ 

                See Also

                Expand source code -Browse git +Browse git
                def displaySetup(app, *show, **options):
                     """Set up all display parameters.
                @@ -1309,7 +1309,7 @@ 

                See Also

                Expand source code -Browse git +Browse git
                def displayShow(app, *options):
                     """Show display parameters.
                @@ -1444,7 +1444,7 @@ 

                Results

                Expand source code -Browse git +Browse git
                def export(app, tuples, toDir=None, toFile="results.tsv", **options):
                     """Exports an iterable of tuples of nodes to an Excel friendly TSV file.
                @@ -1589,7 +1589,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def getCss(app):
                     """Export the CSS for this app.
                @@ -1639,7 +1639,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def getToolCss(app, tool):
                     """Export the CSS for a tool of this app.
                @@ -1689,7 +1689,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def loadCss(app):
                     """Load the CSS for this app.
                @@ -1768,7 +1768,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def loadToolCss(app, tool, extraCss):
                     """Load the Tool CSS for this app.
                @@ -1840,7 +1840,7 @@ 

                Result

                Expand source code -Browse git +Browse git
                def plain(app, n, _inTuple=False, _asString=False, explain=False, **options):
                     """Display the plain text of a node.
                @@ -1926,7 +1926,7 @@ 

                Result

                Expand source code -Browse git +Browse git
                def plainTuple(
                     app,
                @@ -2169,7 +2169,7 @@ 

                Result

                Expand source code -Browse git +Browse git
                def pretty(app, n, explain=False, _asString=False, **options):
                     """Displays the material that corresponds to a node in a graphical way.
                @@ -2248,7 +2248,7 @@ 

                Result

                Expand source code -Browse git +Browse git
                def prettyTuple(app, tup, seq=None, _asString=False, item=RESULT, **options):
                     """Displays the material that corresponds to a tuple of nodes in a graphical way.
                @@ -2361,7 +2361,7 @@ 

                Result

                Expand source code -Browse git +Browse git
                def show(app, tuples, _asString=False, **options):
                     """Displays an iterable of tuples of nodes.
                @@ -2464,7 +2464,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def table(app, tuples, _asString=False, **options):
                     """Plain displays of an iterable of tuples of nodes in a table.
                diff --git a/tf/advanced/find.html b/tf/advanced/find.html
                index 49eca61bd..fa0edada0 100644
                --- a/tf/advanced/find.html
                +++ b/tf/advanced/find.html
                @@ -31,7 +31,7 @@ 

                Module tf.advanced.find

                Expand source code -Browse git +Browse git
                import sys
                 from importlib import util
                @@ -270,7 +270,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def findAppClass(appName, appPath):
                     """Find the class definition of an app.
                @@ -325,7 +325,7 @@ 

                See Also

                Expand source code -Browse git +Browse git
                def findAppConfig(
                     appName,
                @@ -474,7 +474,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def loadModule(moduleName, *args):
                     """Load a module dynamically, by name.
                diff --git a/tf/advanced/helpers.html b/tf/advanced/helpers.html
                index cad24f313..b4ffc5af5 100644
                --- a/tf/advanced/helpers.html
                +++ b/tf/advanced/helpers.html
                @@ -31,7 +31,7 @@ 

                Module tf.advanced.helpers

                Expand source code -Browse git +Browse git
                import collections
                 from textwrap import dedent
                @@ -864,7 +864,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def backendRepl(match):
                     thisBackend.append(match.group(1))
                @@ -894,7 +894,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def dh(html, inNb="ipython", unexpand=False):
                     """Display HTML.
                @@ -952,7 +952,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def dm(md, inNb="ipython", unexpand=False):
                     """Display markdown.
                @@ -995,7 +995,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def getHeaderTypes(app, tuples):
                     api = app.api
                @@ -1034,7 +1034,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def getHeaders(app, tuples):
                     headerTypes = getHeaderTypes(app, tuples)
                @@ -1058,7 +1058,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def getLocalDir(backend, cfg, local, version):
                     provenanceSpec = cfg.get("provenanceSpec", {})
                @@ -1098,7 +1098,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def getResultsX(app, results, features, condenseType, fmt=None):
                     """Transform a uniform iterable of nodes into a table with extra information.
                @@ -1194,7 +1194,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def getRowsX(app, tuples, features, condenseType, fmt=None):
                     """Transform an iterable of nodes into a table with extra information.
                @@ -1218,7 +1218,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def getText(
                     app, isPretty, n, nType, outer, first, last, level, passage, descend, options=None
                @@ -1311,7 +1311,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def getTuplesX(app, results, condenseType, fmt=None):
                     """Transform a non-uniform iterable of nodes into a table with extra information.
                @@ -1379,7 +1379,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def getValue(app, n, nType, feat, suppress, math=False):
                     F = app.api.F
                @@ -1408,7 +1408,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def hData(x):
                     if not x:
                @@ -1439,7 +1439,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def hDict(x, outer=False):
                     elem = f"{'o' if outer else 'u'}l"
                @@ -1469,7 +1469,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def hEmpty(x):
                     return (
                @@ -1491,7 +1491,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def hList(x, outer=False):
                     elem = f"{'o' if outer else 'u'}l"
                @@ -1519,7 +1519,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def hScalar(x):
                     if type(x) is str:
                @@ -1539,7 +1539,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def hScalar0(x):
                     tpv = type(x)
                @@ -1584,7 +1584,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def hasData(backend, local, org, repo, version, relative):
                     versionRep = f"/{version}" if version else ""
                @@ -1609,7 +1609,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def htmlSafe(text, isHtml, math=False):
                     return text.replace("\n", "<br>") if isHtml else htmlEsc(text, math=math)
                @@ -1627,7 +1627,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                def isUniform(app, tuples):
                     """Whether the members of tuples are uniform.
                @@ -1669,7 +1669,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def parseFeatures(features):
                     if (
                @@ -1698,7 +1698,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def parseFeaturesLogical(feats):
                     bare = []
                @@ -1725,7 +1725,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def runsInNotebook():
                     """Determines whether the program runs in an interactive shell.
                @@ -1771,7 +1771,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def showDict(title, data, _browse, inNb, *keys):
                     """Shows selected keys of a dictionary in a pretty way.
                @@ -1812,7 +1812,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def splitModRef(moduleRef):
                     thisBackend.clear()
                @@ -1890,7 +1890,7 @@ 

                See Also

                Expand source code -Browse git +Browse git
                def transitiveClosure(relation, reflexiveExceptions):
                     """Produce the reflexive transitive closure of a relation.
                @@ -1958,7 +1958,7 @@ 

                See Also

                Expand source code -Browse git +Browse git
                def tupleEnum(tuples, start, end, limit, item, inNb):
                     if start is None:
                diff --git a/tf/advanced/highlight.html b/tf/advanced/highlight.html
                index 78b1c1fcb..28c743942 100644
                --- a/tf/advanced/highlight.html
                +++ b/tf/advanced/highlight.html
                @@ -31,7 +31,7 @@ 

                Module tf.advanced.highlight

                Expand source code -Browse git +Browse git
                from .search import runSearch
                 
                @@ -290,7 +290,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def getEdgeHlAtt(e, pair, highlights):
                     """Get the edge highlight attribute and style for an edge, only for pretty mode.
                @@ -370,7 +370,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def getHlAtt(app, n, highlights, isSlot):
                     """Get the highlight attribute and style for a node for both pretty and plain modes.
                @@ -457,7 +457,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def getPassageHighlights(app, node, query, colorMap, cache):
                     """Get the highlights for a whole passage.
                @@ -550,7 +550,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def getTupleHighlights(api, tup, highlights, colorMap, condenseType):
                     """Get the highlights for a tuple of nodes.
                diff --git a/tf/advanced/index.html b/tf/advanced/index.html
                index acfb7cd30..7f363b620 100644
                --- a/tf/advanced/index.html
                +++ b/tf/advanced/index.html
                @@ -66,7 +66,7 @@ 

                Advanced API

                Expand source code -Browse git +Browse git
                """
                 # Advanced API
                diff --git a/tf/advanced/interchange.html b/tf/advanced/interchange.html
                index 4025cb9e6..44fa4b1ca 100644
                --- a/tf/advanced/interchange.html
                +++ b/tf/advanced/interchange.html
                @@ -35,7 +35,7 @@ 

                Module tf.advanced.interchange

                Expand source code -Browse git +Browse git
                """
                 Produce exports of the whole dataset in different formats.
                @@ -86,7 +86,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def interchangeApi(app):
                     """Produce the interchange functions API.
                diff --git a/tf/advanced/links.html b/tf/advanced/links.html
                index 449a22d76..0be9d988e 100644
                --- a/tf/advanced/links.html
                +++ b/tf/advanced/links.html
                @@ -32,7 +32,7 @@ 

                Module tf.advanced.links

                Expand source code -Browse git +Browse git
                """
                 Produce links to TF data and links from nodes to web resources.
                @@ -1100,7 +1100,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def flexLink(app, kind):
                     """Produce documentation links that are heavily dependent on the back-end.
                @@ -1175,7 +1175,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def header(app, allMeta=False):
                     """Generate a colophon of the app.
                @@ -1285,7 +1285,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def linksApi(app, silent=SILENT_D):
                     """Produce the link API.
                @@ -1468,7 +1468,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def outLink(
                     text, href, title=None, passage=None, clsName=None, target="_blank", asHtml=True
                @@ -1540,7 +1540,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def provenanceLink(
                     backend, org, repo, version, branch, commit, local, release, relative
                @@ -1627,7 +1627,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def showProvenance(app, jobName="program code", author="program author"):
                     """Shows the provenance that is normally displayed during data loading.
                @@ -1710,7 +1710,7 @@ 

                See Also

                Expand source code -Browse git +Browse git
                def webLink(
                     app, n, text=None, clsName=None, urlOnly=False, _asString=False, _noUrl=False
                diff --git a/tf/advanced/options.html b/tf/advanced/options.html
                index 51f748ecc..b0ae7dcfa 100644
                --- a/tf/advanced/options.html
                +++ b/tf/advanced/options.html
                @@ -392,7 +392,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                """
                 # Display Settings.
                @@ -1144,7 +1144,7 @@ 

                Classes

                Expand source code -Browse git +Browse git
                class Options:
                     def __init__(self, app):
                @@ -1327,7 +1327,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def check(self, msg, options):
                     app = self.app
                @@ -1389,7 +1389,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def consume(self, options, *remove):
                     return {o: options[o] for o in options if o not in remove}
                @@ -1403,7 +1403,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def distill(self, options):
                     defaults = self.defaults
                @@ -1428,7 +1428,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def normalize(self, option, value):
                     app = self.app
                @@ -1493,7 +1493,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def reset(self, *options):
                     app = self.app
                @@ -1521,7 +1521,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def setup(self, *options, **overrides):
                     app = self.app
                @@ -1549,7 +1549,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                class OptionsCurrent:
                     def __init__(self, options):
                @@ -1574,7 +1574,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def get(self, k, v=None):
                     return getattr(self, k, v)
                @@ -1588,7 +1588,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def set(self, k, v):
                     self.allKeys.add(k)
                diff --git a/tf/advanced/render.html b/tf/advanced/render.html
                index eaf651d27..f8f44e091 100644
                --- a/tf/advanced/render.html
                +++ b/tf/advanced/render.html
                @@ -45,7 +45,7 @@ 

                Information shielding

                Expand source code -Browse git +Browse git
                """
                 # Render
                @@ -807,7 +807,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def render(app, isPretty, n, _inTuple, _asString, explain, **options):
                     """Renders a node, in plain or pretty mode.
                diff --git a/tf/advanced/repo.html b/tf/advanced/repo.html
                index 070eb2b42..8685b7012 100644
                --- a/tf/advanced/repo.html
                +++ b/tf/advanced/repo.html
                @@ -295,7 +295,7 @@ 

                Updating a corpus that you alre
                Expand source code -Browse git +Browse git
                """
                 # Auto downloading from a back-end repository
                @@ -2561,7 +2561,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def GLPERS(backend):
                     return f"GL_{SHELL_VAR_RE.sub('_', backend.upper())}_PERS"
                @@ -2575,7 +2575,7 @@

                Functions

                Expand source code -Browse git +Browse git
                def bumpRelease(latestR, increase):
                     if latestR:
                @@ -2613,7 +2613,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def catchRemaining(e):
                     eType = type(e)
                @@ -2733,7 +2733,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def checkoutRepo(
                     backend,
                @@ -2925,7 +2925,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def extractPrecise(z):
                     """Extracts a zip file precisely, by deleting some pre-existing material.
                @@ -2967,7 +2967,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def getFinalUrl(url):
                     finalUrl = None
                @@ -3024,7 +3024,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def publishRelease(app, increase, message=None, description=None):
                     """Publishes a new data release for a TF dataset to GitHub.
                @@ -3203,7 +3203,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def releaseData(
                     backend,
                @@ -3270,7 +3270,7 @@ 

                Classes

                Expand source code -Browse git +Browse git
                class Checkout:
                     """Auxiliary class for `checkoutRepo`"""
                @@ -4355,7 +4355,7 @@ 

                Static methods

                Expand source code -Browse git +Browse git
                @staticmethod
                 def fromString(string):
                @@ -4392,7 +4392,7 @@ 

                Static methods

                Expand source code -Browse git +Browse git
                @staticmethod
                 def retrieve(url):
                @@ -4423,7 +4423,7 @@ 

                Static methods

                Expand source code -Browse git +Browse git
                @staticmethod
                 def toString(commit, release, local, backend, source=None, dest=None):
                @@ -4466,7 +4466,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def connect(self):
                     conn = self.conn
                @@ -4540,7 +4540,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def display(self, msg, msgPlain):
                     inNb = self.inNb
                @@ -4560,7 +4560,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def download(self):
                     cChk = self.commitChk
                @@ -4585,7 +4585,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def downloadCommit(self, commit, showErrors=True):
                     c = self.getCommitObj(commit)
                @@ -4609,7 +4609,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def downloadComplete(self):
                     ssl._create_default_https_context = ssl._create_unverified_context
                @@ -4698,7 +4698,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def downloadDir(self, commit, exclude=None, showErrors=False):
                     g = self.repoOnline
                @@ -4792,7 +4792,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def downloadRelease(self, release, showErrors=True):
                     cChk = self.commitChk
                @@ -4846,7 +4846,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def downloadZip(self, where, shiftUp=False, commit=None, showErrors=True):
                     # commit parameter only supported for GitLab
                @@ -4987,7 +4987,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def error(self, msg, newline=True):
                     console(msg, error=True, newline=newline)
                @@ -5001,7 +5001,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def fetchInfo(self):
                     if self.isOffline():
                @@ -5039,7 +5039,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def fixInfo(self):
                     sDir = self.dirPathLocal
                @@ -5063,7 +5063,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def getCommit(self, commit):
                     c = self.getCommitObj(commit)
                @@ -5080,7 +5080,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def getCommitFromObj(self, c):
                     g = self.repoOnline
                @@ -5100,7 +5100,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def getCommitObj(self, commit):
                     g = self.repoOnline
                @@ -5153,7 +5153,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def getRelease(self, release, showErrors=True):
                     r = self.getReleaseObj(release, showErrors=showErrors)
                @@ -5170,7 +5170,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def getReleaseFromObj(self, r):
                     g = self.repoOnline
                @@ -5197,7 +5197,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def getReleaseObj(self, release, showErrors=True):
                     g = self.repoOnline
                @@ -5247,7 +5247,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def info(self, msg, newline=True):
                     silent = self.silent
                @@ -5263,7 +5263,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def isClone(self):
                     return self.local == "clone"
                @@ -5277,7 +5277,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def isExpress(self):
                     return (
                @@ -5296,7 +5296,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def isOffline(self):
                     return self.local in {"clone", "local"}
                @@ -5310,7 +5310,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def login(self):
                     onGithub = self.onGithub
                @@ -5392,7 +5392,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def makeSureLocal(self, attempt=False):
                     _browse = self._browse
                @@ -5600,7 +5600,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def possibleError(self, msg, showErrors, again=False, indent="\t", newline=False):
                     if showErrors:
                @@ -5619,7 +5619,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def readInfo(self):
                     if fileExists(self.filePathLocal):
                @@ -5641,7 +5641,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def warning(self, msg, newline=True):
                     silent = self.silent
                @@ -5657,7 +5657,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def writeInfo(self, release=None, commit=None):
                     releaseOff = self.releaseOff if release is None else release
                @@ -5681,7 +5681,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                class Repo:
                     """Auxiliary class for `releaseData`"""
                @@ -5968,7 +5968,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def bumpRelease(self):
                     increase = self.increase
                @@ -5986,7 +5986,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def connect(self):
                     backend = self.backend
                @@ -6053,7 +6053,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def error(self, msg, newline=True):
                     console(msg, error=True, newline=newline)
                @@ -6067,7 +6067,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def fetchInfo(self):
                     g = self.repoOnline
                @@ -6093,7 +6093,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def getCommit(self):
                     c = self.getCommitObj()
                @@ -6110,7 +6110,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def getCommitObj(self):
                     g = self.repoOnline
                @@ -6139,7 +6139,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def getRelease(self):
                     r = self.getReleaseObj()
                @@ -6156,7 +6156,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def getReleaseObj(self):
                     g = self.repoOnline
                @@ -6184,7 +6184,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def info(self, msg, newline=True):
                     silent = self.silent
                @@ -6200,7 +6200,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def makeRelease(self):
                     g = self.repoOnline
                @@ -6239,7 +6239,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def makeZip(self):
                     source = self.source
                @@ -6276,7 +6276,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def newRelease(self):
                     if not self.makeZip():
                @@ -6312,7 +6312,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def uploadZip(self):
                     newTag = self.newTag
                @@ -6351,7 +6351,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def warning(self, msg, newline=True):
                     silent = self.silent
                diff --git a/tf/advanced/search.html b/tf/advanced/search.html
                index 7096629fe..cf21965d0 100644
                --- a/tf/advanced/search.html
                +++ b/tf/advanced/search.html
                @@ -32,7 +32,7 @@ 

                Module tf.advanced.search

                Expand source code -Browse git +Browse git
                """
                 Calls from the advanced API to the Search API.
                @@ -315,7 +315,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def getQueryFeatures(exe):
                     qnodes = getattr(exe, "qnodes", [])
                @@ -355,7 +355,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def runSearch(app, query, cache):
                     """A wrapper around the generic search interface of TF.
                @@ -424,7 +424,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def runSearchCondensed(app, query, cache, condenseType):
                     """A wrapper around the generic search interface of TF.
                @@ -544,7 +544,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def search(
                     app, query, silent=SILENT_D, sets=None, shallow=False, sort=True, limit=None
                @@ -708,7 +708,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def searchApi(app):
                     app.search = types.MethodType(search, app)
                diff --git a/tf/advanced/sections.html b/tf/advanced/sections.html index d8de08718..71cb1366c 100644 --- a/tf/advanced/sections.html +++ b/tf/advanced/sections.html @@ -49,7 +49,7 @@

                Structure

                Expand source code -Browse git +Browse git
                """Section
                 
                @@ -312,7 +312,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def nodeFromSectionStr(app, sectionStr, lang="en"):
                     """Find the node of a section string.
                @@ -430,7 +430,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def sectionStrFromNode(app, n, lang="en", lastSlot=False, fillup=False):
                     """The heading of a section to which a node belongs.
                @@ -483,7 +483,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def sectionsApi(app):
                     app.nodeFromSectionStr = types.MethodType(nodeFromSectionStr, app)
                @@ -509,7 +509,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def structureStrFromNode(app, n):
                     """The heading of a structure to which a node belongs.
                diff --git a/tf/advanced/settings.html b/tf/advanced/settings.html
                index 5fb65b56b..d0cc9c009 100644
                --- a/tf/advanced/settings.html
                +++ b/tf/advanced/settings.html
                @@ -844,7 +844,7 @@ 

                writing

                Expand source code -Browse git +Browse git
                """
                 # App settings
                @@ -2862,7 +2862,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def DOC_DEFAULTS(backend):
                     return (
                @@ -2886,7 +2886,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def compileFormatCls(app, specs, givenStyles):
                     api = app.api
                @@ -2930,7 +2930,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def getDataDefaults(app, cfg, dKey, withApi):
                     checker = Check(app, withApi)
                @@ -2993,7 +2993,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def getLevel(defaultLevel, givenInfo, isVerse):
                     level = givenInfo.get("level", defaultLevel)
                @@ -3013,7 +3013,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def getTypeDefaults(app, cfg, dKey, withApi):
                     if not withApi:
                @@ -3336,7 +3336,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def setAppSpecs(app, cfg, reset=False):
                     backend = app.backend
                @@ -3440,7 +3440,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def setAppSpecsApi(app, cfg):
                     api = app.api
                @@ -3519,7 +3519,7 @@ 

                See Also

                Expand source code -Browse git +Browse git
                def showContext(app, *keys, withComputed=True, asHtml=False):
                     """Shows the *context* of the app `tf.advanced.app.App.context` in a pretty way.
                @@ -3585,7 +3585,7 @@ 

                Classes

                Expand source code -Browse git +Browse git
                class AppCurrent:
                     def __init__(self, specs):
                @@ -3615,7 +3615,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def get(self, k, v):
                     return getattr(self, k, v)
                @@ -3629,7 +3629,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def set(self, k, v):
                     self.allKeys.add(k)
                @@ -3644,7 +3644,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def update(self, specs):
                     allKeys = self.allKeys
                @@ -3664,7 +3664,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                class Check:
                     def __init__(self, app, withApi):
                @@ -3867,7 +3867,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def checkGroup(self, cfg, defaults, dKey, postpone=set(), extra=None):
                     self.cfg = cfg
                @@ -3895,7 +3895,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def checkItem(self, cfg, dKey):
                     self.cfg = cfg
                @@ -3915,7 +3915,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def checkSetting(self, k, v, extra=None):
                     app = self.app
                @@ -4074,7 +4074,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def report(self):
                     errors = self.errors
                diff --git a/tf/advanced/tables.html b/tf/advanced/tables.html
                index 624d14aaa..29a89f47d 100644
                --- a/tf/advanced/tables.html
                +++ b/tf/advanced/tables.html
                @@ -31,7 +31,7 @@ 

                Module tf.advanced.tables

                Expand source code -Browse git +Browse git
                from ..core.text import DEFAULT_FORMAT
                 from .helpers import getHeaders, RESULT
                @@ -416,7 +416,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def compose(
                     app,
                @@ -542,7 +542,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def composeP(
                     app,
                @@ -651,7 +651,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def composeT(
                     app,
                diff --git a/tf/advanced/text.html b/tf/advanced/text.html
                index d87034435..5aa0ecdc3 100644
                --- a/tf/advanced/text.html
                +++ b/tf/advanced/text.html
                @@ -31,7 +31,7 @@ 

                Module tf.advanced.text

                Expand source code -Browse git +Browse git
                import types
                 from textwrap import dedent
                @@ -199,7 +199,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def showFormats(app):
                     inNb = app.inNb
                @@ -253,7 +253,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def specialCharacters(app, fmt=None, _browse=False):
                     """Generate a widget for hard to type characters.
                @@ -349,7 +349,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def textApi(app):
                     api = app.api
                diff --git a/tf/advanced/unravel.html b/tf/advanced/unravel.html
                index a875dc706..c5c27fbf4 100644
                --- a/tf/advanced/unravel.html
                +++ b/tf/advanced/unravel.html
                @@ -35,7 +35,7 @@ 

                Unravel

                Expand source code -Browse git +Browse git
                """
                 # Unravel
                @@ -746,7 +746,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def unravel(app, n, isPlain=True, _inTuple=False, explain=False, **options):
                     """Unravels a node and its graph-neighbourhood into a tree of fragments.
                @@ -801,7 +801,7 @@ 

                Classes

                Expand source code -Browse git +Browse git
                class NodeProps:
                     """Node properties during plain() or pretty().
                @@ -894,7 +894,7 @@ 

                Instance variables

                Expand source code -Browse git +Browse git
                class OuterSettings:
                     """Common properties during plain() and pretty().
                @@ -976,7 +976,7 @@ 

                Instance variables

                Expand source code -Browse git +Browse git
                class TreeInfo:
                     """Tree properties during plain() or pretty().
                @@ -1004,7 +1004,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def get(self, k, v):
                     return getattr(self, k, v)
                @@ -1018,7 +1018,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def update(self, **specs):
                     for (k, v) in specs.items():
                diff --git a/tf/advanced/volumes.html b/tf/advanced/volumes.html
                index 5f179c311..1cf2c3629 100644
                --- a/tf/advanced/volumes.html
                +++ b/tf/advanced/volumes.html
                @@ -32,7 +32,7 @@ 

                Module tf.advanced.volumes

                Expand source code -Browse git +Browse git
                """
                 Produce links to TF data and links from nodes to web resources.
                @@ -141,7 +141,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def collect(app, *args, **kwargs):
                     """Calls `tf.fabric.Fabric.collect` from an app object."""
                @@ -161,7 +161,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def extract(app, *args, **kwargs):
                     """Calls `tf.fabric.Fabric.extract` from an app object."""
                @@ -189,7 +189,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def getVolumes(app, *args, **kwargs):
                     """Calls `tf.fabric.Fabric.getVolumes` from an app object.
                @@ -229,7 +229,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def volumesApi(app):
                     """Produce the volume support functions API.
                diff --git a/tf/advanced/zipdata.html b/tf/advanced/zipdata.html
                index 28c6c2f9c..043e002b7 100644
                --- a/tf/advanced/zipdata.html
                +++ b/tf/advanced/zipdata.html
                @@ -31,7 +31,7 @@ 

                Module tf.advanced.zipdata

                Expand source code -Browse git +Browse git
                import sys
                 import types
                @@ -473,7 +473,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def addCheckout(path):
                     release = None
                @@ -512,7 +512,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def collectFiles(base, path, results, zipBase=None):
                     if zipBase is None:
                @@ -560,7 +560,7 @@ 

                EFFECT

                Expand source code -Browse git +Browse git
                def main(cargs=sys.argv):
                     if len(cargs) < 2 or any(
                @@ -640,7 +640,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def zipAll(app):
                     """Gathers all data for a TF resource and zips it into one file.
                @@ -781,7 +781,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def zipApi(app):
                     """Produce the zip creation API.
                @@ -827,7 +827,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def zipData(
                     backend,
                @@ -956,7 +956,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def zipDataPart(source, results):
                     if not dirExists(source):
                diff --git a/tf/app.html b/tf/app.html
                index a55fe4554..cf7fa6bed 100644
                --- a/tf/app.html
                +++ b/tf/app.html
                @@ -39,7 +39,7 @@ 

                Module tf.app

                Expand source code -Browse git +Browse git
                """
                 Make use of a corpus.
                @@ -137,7 +137,7 @@ 

                See Also

                Expand source code -Browse git +Browse git
                def use(appName, *args, backend=None, **kwargs):
                     """Make use of a corpus.
                diff --git a/tf/browser/command.html b/tf/browser/command.html
                index 0c66cf9e7..12d56f56b 100644
                --- a/tf/browser/command.html
                +++ b/tf/browser/command.html
                @@ -32,7 +32,7 @@ 

                Module tf.browser.command

                Expand source code -Browse git +Browse git
                """
                 Command-line argument processing
                @@ -156,7 +156,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def argApp(cargs, simple):
                     (appName, checkoutApp, dataLoc) = argParam(cargs)
                @@ -212,7 +212,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def argNoweb(cargs):
                     for arg in cargs:
                @@ -229,7 +229,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def argParam(cargs):
                     appName = None
                @@ -269,7 +269,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def getPort(slug):
                     portOffset = crc32(slug.encode("utf8")) % 10000
                diff --git a/tf/browser/html.html b/tf/browser/html.html
                index 704d392d2..4fcfd5d2d 100644
                --- a/tf/browser/html.html
                +++ b/tf/browser/html.html
                @@ -34,7 +34,7 @@ 

                Module tf.browser.html

                Expand source code -Browse git +Browse git
                """HTML generation done in the Pythonic way.
                 
                @@ -42,7 +42,7 @@ 

                Module tf.browser.html

                `tf.browser.ner.ner` . """ from ..core.generic import isIterable -from ..core.helpers import console +from ..core.helpers import console, NBSP H_ELEMENT_DEFS = """ @@ -169,7 +169,7 @@

                Module tf.browser.html

                For each HTML element in the specs (`H_ELEMENTS`) a corresponding generating function is added as method. """ - nb = "\u00a0" + nb = NBSP setattr(H, "join", dig) @@ -223,7 +223,7 @@

                Returns

                Expand source code -Browse git +Browse git
                def dig(*content, sep=""):
                     """A method to join nested iterables of strings into a string.
                @@ -274,7 +274,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def elemFunc(close, elem):
                     """Generates a function to serialize a specific HTML element.
                @@ -330,7 +330,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def generate(close, tag, *content, **atts):
                     """Transform the logical information for an HTML element into an HTML string.
                @@ -384,7 +384,7 @@ 

                Classes

                Expand source code -Browse git +Browse git
                class H:
                     """Provider of HTML serializing functions per element type.
                @@ -394,7 +394,7 @@ 

                Classes

                For each HTML element in the specs (`H_ELEMENTS`) a corresponding generating function is added as method. """ - nb = "\u00a0"
                + nb = NBSP

                Class variables

                @@ -413,7 +413,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def result(*content, **atts):
                     return generate(close, elem, *content, **atts)
                @@ -427,7 +427,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def result(**atts):
                     return generate(close, elem, **atts)
                @@ -441,7 +441,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def result(*content, **atts):
                     return generate(close, elem, *content, **atts)
                @@ -455,7 +455,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def result(*content, **atts):
                     return generate(close, elem, *content, **atts)
                @@ -469,7 +469,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def result(*content, **atts):
                     return generate(close, elem, *content, **atts)
                @@ -483,7 +483,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def result(*content, **atts):
                     return generate(close, elem, *content, **atts)
                @@ -497,7 +497,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def result(*content, **atts):
                     return generate(close, elem, *content, **atts)
                @@ -511,7 +511,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def result(**atts):
                     return generate(close, elem, **atts)
                @@ -537,7 +537,7 @@

                Returns

                Expand source code -Browse git +Browse git
                def dig(*content, sep=""):
                     """A method to join nested iterables of strings into a string.
                @@ -575,7 +575,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def result(*content, **atts):
                     return generate(close, elem, *content, **atts)
                @@ -589,7 +589,7 @@

                Returns

                Expand source code -Browse git +Browse git
                def result(*content, **atts):
                     return generate(close, elem, *content, **atts)
                @@ -603,7 +603,7 @@

                Returns

                Expand source code -Browse git +Browse git
                def result(*content, **atts):
                     return generate(close, elem, *content, **atts)
                @@ -617,7 +617,7 @@

                Returns

                Expand source code -Browse git +Browse git
                def result(*content, **atts):
                     return generate(close, elem, *content, **atts)
                @@ -631,7 +631,7 @@

                Returns

                Expand source code -Browse git +Browse git
                def result(*content, **atts):
                     return generate(close, elem, *content, **atts)
                @@ -645,7 +645,7 @@

                Returns

                Expand source code -Browse git +Browse git
                def result(*content, **atts):
                     return generate(close, elem, *content, **atts)
                diff --git a/tf/browser/index.html b/tf/browser/index.html index 59e654c08..aee0ccded 100644 --- a/tf/browser/index.html +++ b/tf/browser/index.html @@ -32,7 +32,7 @@

                Local TF data and web server

                Expand source code -Browse git +Browse git
                """
                 # Local TF data and web server
                diff --git a/tf/browser/kernel.html b/tf/browser/kernel.html
                index 226f17851..6816aa4ce 100644
                --- a/tf/browser/kernel.html
                +++ b/tf/browser/kernel.html
                @@ -38,7 +38,7 @@ 

                Kernel API

                Expand source code -Browse git +Browse git
                """
                 # TF kernel
                @@ -550,7 +550,7 @@ 

                Functions

                Expand source code -Browse git +Browse git
                def makeTfKernel(app, appName):
                     if not app.api:
                diff --git a/tf/browser/ner/corpus.html b/tf/browser/ner/corpus.html
                index 3c2d13127..4b39dc1d6 100644
                --- a/tf/browser/ner/corpus.html
                +++ b/tf/browser/ner/corpus.html
                @@ -39,7 +39,7 @@ 

                Module tf.browser.ner.corpus

                Expand source code -Browse git +Browse git
                """Access to the corpus.
                 
                @@ -89,14 +89,13 @@ 

                Module tf.browser.ner.corpus

                self.appName = appName self.version = version - (specDir, annoDir, reportDir) = annotateDir(app, TOOLKEY) + (specDir, annoDir) = annotateDir(app, TOOLKEY) self.specDir = specDir self.annoDir = f"{annoDir}/{version}" self.sheetDir = f"{specDir}/specs" - self.reportBase = f"{reportDir}/{version}" - super().__init__() + Settings.__init__(self) api = app.api F = api.F @@ -455,7 +454,7 @@

                Classes

                Expand source code -Browse git +Browse git
                class Corpus(Settings):
                     def __init__(self):
                @@ -479,14 +478,13 @@ 

                Classes

                self.appName = appName self.version = version - (specDir, annoDir, reportDir) = annotateDir(app, TOOLKEY) + (specDir, annoDir) = annotateDir(app, TOOLKEY) self.specDir = specDir self.annoDir = f"{annoDir}/{version}" self.sheetDir = f"{specDir}/specs" - self.reportBase = f"{reportDir}/{version}" - super().__init__() + Settings.__init__(self) api = app.api F = api.F diff --git a/tf/browser/ner/data.html b/tf/browser/ner/data.html index 73b4cc415..ab48d1cfa 100644 --- a/tf/browser/ner/data.html +++ b/tf/browser/ner/data.html @@ -43,7 +43,7 @@

                Module tf.browser.ner.data

                Expand source code -Browse git +Browse git
                """Annotation data module.
                 
                @@ -112,7 +112,8 @@ 

                Module tf.browser.ner.data

                In that way, the `Data` object can start with the sets already in memory. """ - super().__init__() + Corpus.__init__(self) + if not self.properlySetup: return @@ -121,7 +122,7 @@

                Module tf.browser.ner.data

                annoDir = self.annoDir initTree(annoDir, fresh=False) - def loadSetData(self): + def loadSetData(self, _lowlevel=False): """Loads the current annotation set into memory. It has two phases: @@ -141,6 +142,20 @@

                Module tf.browser.ner.data

                changed = self.fromSourceSet() self.processSet(changed) + def _clearSetData(self): + """Clears the current annotation set data from memory. + """ + if not self.properlySetup: + return + + sets = self.sets + setName = self.setName + + setData = AttrDict() + setData.entities = AttrDict() + sets[setName] = setData + self.processSet(True) + def fromSourceSet(self): """Loads an annotation set from source. @@ -164,6 +179,7 @@

                Module tf.browser.ner.data

                settings = self.settings setName = self.setName + setIsSrc = self.setIsSrc setData = self.sets[setName] annoDir = self.annoDir @@ -184,7 +200,25 @@

                Module tf.browser.ner.data

                changed = False - if setName: + if setIsSrc: + if "entities" not in setData: + entities = {} + hasFeature = {feat: checkFeature(feat) for feat in features} + + for e in self.getEntityNodes(): + slots = getSlots(e) + entities[e] = ( + tuple( + getFVal(feat, e) + if hasFeature[feat] + else featureDefault[feat](slots) + for feat in features + ), + tuple(slots), + ) + + setData.entities = entities + else: if ( "entities" not in setData or "dateLoaded" not in setData @@ -205,24 +239,6 @@

                Module tf.browser.ner.data

                setData.entities = entities setData.dateLoaded = time.time() - else: - if "entities" not in setData: - entities = {} - hasFeature = {feat: checkFeature(feat) for feat in features} - - for e in self.getEntityNodes(): - slots = getSlots(e) - entities[e] = ( - tuple( - getFVal(feat, e) - if hasFeature[feat] - else featureDefault[feat](slots) - for feat in features - ), - tuple(slots), - ) - - setData.entities = entities return changed @@ -419,10 +435,10 @@

                Module tf.browser.ner.data

                if not self.properlySetup: return - setName = self.setName + setIsRo = self.setIsRo setNameRep = self.setNameRep - if not setName: + if setIsRo: if silent: return (-1, -1) self.console(f"Entity deletion not allowed on {setNameRep}", error=True) @@ -499,11 +515,11 @@

                Module tf.browser.ner.data

                if not self.properlySetup: return - setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo browse = self.browse - if not setName: + if setIsRo: msg = f"Entity deletion not allowed on {setNameRep}" if browse: return [[msg]] @@ -625,10 +641,10 @@

                Module tf.browser.ner.data

                if not self.properlySetup: return - setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo - if not setName: + if setIsRo: if silent: return (-1, -1) self.console(f"Entity addition not allowed on {setNameRep}", error=True) @@ -670,7 +686,7 @@

                Module tf.browser.ner.data

                self.console(f"Already present: {present:>5} x") self.console(f"Added: {added:>5} x") - def addEntities(self, newEntities, silent=True): + def addEntities(self, newEntities, silent=True, _lowlevel=False): """Add multiple entities efficiently to the current set. This operation is not allowed if the current set is the read-only set with the @@ -680,7 +696,6 @@

                Module tf.browser.ner.data

                the corpus to find them. This method does them all in one fell swoop. - It is used by the method `tf.browser.ner.ner.NER.markEntities()`. Parameters ---------- @@ -705,15 +720,19 @@

                Module tf.browser.ner.data

                if not self.properlySetup: return - setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo + setIsSrc = self.setIsSrc - if not setName: + if not _lowlevel and setIsRo: if silent: return (-1, -1) self.console(f"Entities addition not allowed on {setNameRep}", error=True) return + if _lowlevel and (setIsSrc or not setIsRo): + return + setData = self.getSetData() oldEntities = set(setData.entities.values()) @@ -734,12 +753,15 @@

                Module tf.browser.ner.data

                addE.add((fVals, slots)) if len(addE): - self.mergeEntities(addE) + self.mergeEntities(addE, _lowlevel=_lowlevel) self.loadSetData() if silent: return (present, added) + if _lowlevel: + return + self.console(f"Already present: {present:>5} x") self.console(f"Added: {added:>5} x") @@ -778,11 +800,11 @@

                Module tf.browser.ner.data

                if not self.properlySetup: return - setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo browse = self.browse - if not setName: + if setIsRo: msg = f"Entity addition not allowed on {setNameRep}" if browse: return [[msg]] @@ -880,8 +902,9 @@

                Module tf.browser.ner.data

                setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo - if not setName: + if setIsRo: self.console(f"Entity weeding not allowed on {setNameRep}", error=True) return @@ -908,7 +931,7 @@

                Module tf.browser.ner.data

                with fileOpen(dataFile, mode="w") as fh: fh.write("".join(newEntities)) - def mergeEntities(self, newEntities): + def mergeEntities(self, newEntities, _lowlevel=False): """Performs additions to the current annotation set. This operation is not allowed if the current set is the read-only set with the @@ -925,11 +948,16 @@

                Module tf.browser.ner.data

                setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo + setIsSrc = self.setIsSrc - if not setName: + if not _lowlevel and setIsRo: self.console(f"Entity merging not allowed on {setNameRep}", error=True) return + if _lowlevel and (setIsSrc or not setIsRo): + return + annoDir = self.annoDir dataFile = f"{annoDir}/{setName}/entities.tsv" @@ -975,10 +1003,10 @@

                Module tf.browser.ner.data

                if not self.properlySetup: return - setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo - if not setName: + if setIsRo: self.console( f"Entity consolidation not meaningful on {setNameRep}", error=True ) @@ -999,8 +1027,8 @@

                Module tf.browser.ner.data

                ) slotLink = {} - nodeFeatures = {feat: {} for feat in features} - edgeFeatures = dict(eoccs={}) + nodeFeatures = AttrDict({feat: {} for feat in features}) + edgeFeatures = AttrDict(eoccs={}) entities = {} n = 0 @@ -1015,7 +1043,7 @@

                Module tf.browser.ner.data

                entities.setdefault(fVals, []).append(n) nEntityOccs = len(entityOccs) - occEdge = edgeFeatures["eoccs"] + occEdge = edgeFeatures.eoccs for fVals, occs in entities.items(): n += 1 @@ -1030,7 +1058,7 @@

                Module tf.browser.ner.data

                self.console(f"{nEntityOccs:>6} entity occurrences") self.console(f"{nEntities:>6} distinct entities") - featureMeta["eoccs"] = dict( + featureMeta.eoccs = dict( valueType="str", description="from entity nodes to their occurrence nodes", ) @@ -1144,7 +1172,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                class Data(Corpus):
                     def __init__(self, sets=None):
                @@ -1175,7 +1203,8 @@ 

                Parameters

                In that way, the `Data` object can start with the sets already in memory. """ - super().__init__() + Corpus.__init__(self) + if not self.properlySetup: return @@ -1184,7 +1213,7 @@

                Parameters

                annoDir = self.annoDir initTree(annoDir, fresh=False) - def loadSetData(self): + def loadSetData(self, _lowlevel=False): """Loads the current annotation set into memory. It has two phases: @@ -1204,6 +1233,20 @@

                Parameters

                changed = self.fromSourceSet() self.processSet(changed) + def _clearSetData(self): + """Clears the current annotation set data from memory. + """ + if not self.properlySetup: + return + + sets = self.sets + setName = self.setName + + setData = AttrDict() + setData.entities = AttrDict() + sets[setName] = setData + self.processSet(True) + def fromSourceSet(self): """Loads an annotation set from source. @@ -1227,6 +1270,7 @@

                Parameters

                settings = self.settings setName = self.setName + setIsSrc = self.setIsSrc setData = self.sets[setName] annoDir = self.annoDir @@ -1247,7 +1291,25 @@

                Parameters

                changed = False - if setName: + if setIsSrc: + if "entities" not in setData: + entities = {} + hasFeature = {feat: checkFeature(feat) for feat in features} + + for e in self.getEntityNodes(): + slots = getSlots(e) + entities[e] = ( + tuple( + getFVal(feat, e) + if hasFeature[feat] + else featureDefault[feat](slots) + for feat in features + ), + tuple(slots), + ) + + setData.entities = entities + else: if ( "entities" not in setData or "dateLoaded" not in setData @@ -1268,24 +1330,6 @@

                Parameters

                setData.entities = entities setData.dateLoaded = time.time() - else: - if "entities" not in setData: - entities = {} - hasFeature = {feat: checkFeature(feat) for feat in features} - - for e in self.getEntityNodes(): - slots = getSlots(e) - entities[e] = ( - tuple( - getFVal(feat, e) - if hasFeature[feat] - else featureDefault[feat](slots) - for feat in features - ), - tuple(slots), - ) - - setData.entities = entities return changed @@ -1482,10 +1526,10 @@

                Parameters

                if not self.properlySetup: return - setName = self.setName + setIsRo = self.setIsRo setNameRep = self.setNameRep - if not setName: + if setIsRo: if silent: return (-1, -1) self.console(f"Entity deletion not allowed on {setNameRep}", error=True) @@ -1562,11 +1606,11 @@

                Parameters

                if not self.properlySetup: return - setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo browse = self.browse - if not setName: + if setIsRo: msg = f"Entity deletion not allowed on {setNameRep}" if browse: return [[msg]] @@ -1688,10 +1732,10 @@

                Parameters

                if not self.properlySetup: return - setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo - if not setName: + if setIsRo: if silent: return (-1, -1) self.console(f"Entity addition not allowed on {setNameRep}", error=True) @@ -1733,7 +1777,7 @@

                Parameters

                self.console(f"Already present: {present:>5} x") self.console(f"Added: {added:>5} x") - def addEntities(self, newEntities, silent=True): + def addEntities(self, newEntities, silent=True, _lowlevel=False): """Add multiple entities efficiently to the current set. This operation is not allowed if the current set is the read-only set with the @@ -1743,7 +1787,6 @@

                Parameters

                the corpus to find them. This method does them all in one fell swoop. - It is used by the method `tf.browser.ner.ner.NER.markEntities()`. Parameters ---------- @@ -1768,15 +1811,19 @@

                Parameters

                if not self.properlySetup: return - setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo + setIsSrc = self.setIsSrc - if not setName: + if not _lowlevel and setIsRo: if silent: return (-1, -1) self.console(f"Entities addition not allowed on {setNameRep}", error=True) return + if _lowlevel and (setIsSrc or not setIsRo): + return + setData = self.getSetData() oldEntities = set(setData.entities.values()) @@ -1797,12 +1844,15 @@

                Parameters

                addE.add((fVals, slots)) if len(addE): - self.mergeEntities(addE) + self.mergeEntities(addE, _lowlevel=_lowlevel) self.loadSetData() if silent: return (present, added) + if _lowlevel: + return + self.console(f"Already present: {present:>5} x") self.console(f"Added: {added:>5} x") @@ -1841,11 +1891,11 @@

                Parameters

                if not self.properlySetup: return - setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo browse = self.browse - if not setName: + if setIsRo: msg = f"Entity addition not allowed on {setNameRep}" if browse: return [[msg]] @@ -1943,8 +1993,9 @@

                Parameters

                setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo - if not setName: + if setIsRo: self.console(f"Entity weeding not allowed on {setNameRep}", error=True) return @@ -1971,7 +2022,7 @@

                Parameters

                with fileOpen(dataFile, mode="w") as fh: fh.write("".join(newEntities)) - def mergeEntities(self, newEntities): + def mergeEntities(self, newEntities, _lowlevel=False): """Performs additions to the current annotation set. This operation is not allowed if the current set is the read-only set with the @@ -1988,11 +2039,16 @@

                Parameters

                setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo + setIsSrc = self.setIsSrc - if not setName: + if not _lowlevel and setIsRo: self.console(f"Entity merging not allowed on {setNameRep}", error=True) return + if _lowlevel and (setIsSrc or not setIsRo): + return + annoDir = self.annoDir dataFile = f"{annoDir}/{setName}/entities.tsv" @@ -2038,10 +2094,10 @@

                Parameters

                if not self.properlySetup: return - setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo - if not setName: + if setIsRo: self.console( f"Entity consolidation not meaningful on {setNameRep}", error=True ) @@ -2062,8 +2118,8 @@

                Parameters

                ) slotLink = {} - nodeFeatures = {feat: {} for feat in features} - edgeFeatures = dict(eoccs={}) + nodeFeatures = AttrDict({feat: {} for feat in features}) + edgeFeatures = AttrDict(eoccs={}) entities = {} n = 0 @@ -2078,7 +2134,7 @@

                Parameters

                entities.setdefault(fVals, []).append(n) nEntityOccs = len(entityOccs) - occEdge = edgeFeatures["eoccs"] + occEdge = edgeFeatures.eoccs for fVals, occs in entities.items(): n += 1 @@ -2093,7 +2149,7 @@

                Parameters

                self.console(f"{nEntityOccs:>6} entity occurrences") self.console(f"{nEntities:>6} distinct entities") - featureMeta["eoccs"] = dict( + featureMeta.eoccs = dict( valueType="str", description="from entity nodes to their occurrence nodes", ) @@ -2186,8 +2242,7 @@

                Methods

                empty name.

                If you have multiple entities to add, it is wasteful to do multiple passes over the corpus to find them.

                -

                This method does them all in one fell swoop. -It is used by the method NER.markEntities().

                +

                This method does them all in one fell swoop.

                Parameters

                newEntites : iterable of tuples of tuples
                @@ -2211,9 +2266,9 @@

                Returns

                Expand source code -Browse git +Browse git -
                def addEntities(self, newEntities, silent=True):
                +
                def addEntities(self, newEntities, silent=True, _lowlevel=False):
                     """Add multiple entities efficiently to the current set.
                 
                     This operation is not allowed if the current set is the read-only set with the
                @@ -2223,7 +2278,6 @@ 

                Returns

                the corpus to find them. This method does them all in one fell swoop. - It is used by the method `tf.browser.ner.ner.NER.markEntities()`. Parameters ---------- @@ -2248,15 +2302,19 @@

                Returns

                if not self.properlySetup: return - setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo + setIsSrc = self.setIsSrc - if not setName: + if not _lowlevel and setIsRo: if silent: return (-1, -1) self.console(f"Entities addition not allowed on {setNameRep}", error=True) return + if _lowlevel and (setIsSrc or not setIsRo): + return + setData = self.getSetData() oldEntities = set(setData.entities.values()) @@ -2277,12 +2335,15 @@

                Returns

                addE.add((fVals, slots)) if len(addE): - self.mergeEntities(addE) + self.mergeEntities(addE, _lowlevel=_lowlevel) self.loadSetData() if silent: return (present, added) + if _lowlevel: + return + self.console(f"Already present: {present:>5} x") self.console(f"Added: {added:>5} x")
                @@ -2319,7 +2380,7 @@

                Returns

                Expand source code -Browse git +Browse git
                def addEntity(self, vals, allMatches, silent=True):
                     """Add entity occurrences to the current set.
                @@ -2356,10 +2417,10 @@ 

                Returns

                if not self.properlySetup: return - setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo - if not setName: + if setIsRo: if silent: return (-1, -1) self.console(f"Entity addition not allowed on {setNameRep}", error=True) @@ -2436,7 +2497,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                def addEntityRich(self, additions, buckets, excludedTokens=set()):
                     """Add specified entity occurrences to the current set.
                @@ -2473,11 +2534,11 @@ 

                Parameters

                if not self.properlySetup: return - setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo browse = self.browse - if not setName: + if setIsRo: msg = f"Entity addition not allowed on {setNameRep}" if browse: return [[msg]] @@ -2576,7 +2637,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                def consolidateEntities(self, versionExtension):
                     """Consolidates the current entities as nodes into a new TF data source.
                @@ -2594,10 +2655,10 @@ 

                Parameters

                if not self.properlySetup: return - setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo - if not setName: + if setIsRo: self.console( f"Entity consolidation not meaningful on {setNameRep}", error=True ) @@ -2618,8 +2679,8 @@

                Parameters

                ) slotLink = {} - nodeFeatures = {feat: {} for feat in features} - edgeFeatures = dict(eoccs={}) + nodeFeatures = AttrDict({feat: {} for feat in features}) + edgeFeatures = AttrDict(eoccs={}) entities = {} n = 0 @@ -2634,7 +2695,7 @@

                Parameters

                entities.setdefault(fVals, []).append(n) nEntityOccs = len(entityOccs) - occEdge = edgeFeatures["eoccs"] + occEdge = edgeFeatures.eoccs for fVals, occs in entities.items(): n += 1 @@ -2649,7 +2710,7 @@

                Parameters

                self.console(f"{nEntityOccs:>6} entity occurrences") self.console(f"{nEntities:>6} distinct entities") - featureMeta["eoccs"] = dict( + featureMeta.eoccs = dict( valueType="str", description="from entity nodes to their occurrence nodes", ) @@ -2757,7 +2818,7 @@

                Returns

                Expand source code -Browse git +Browse git
                def delEntity(self, vals, allMatches=None, silent=True):
                     """Delete entity occurrences from the current set.
                @@ -2796,10 +2857,10 @@ 

                Returns

                if not self.properlySetup: return - setName = self.setName + setIsRo = self.setIsRo setNameRep = self.setNameRep - if not setName: + if setIsRo: if silent: return (-1, -1) self.console(f"Entity deletion not allowed on {setNameRep}", error=True) @@ -2876,7 +2937,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                def delEntityRich(self, deletions, buckets, excludedTokens=set()):
                     """Delete specified entity occurrences from the current set.
                @@ -2913,11 +2974,11 @@ 

                Parameters

                if not self.properlySetup: return - setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo browse = self.browse - if not setName: + if setIsRo: msg = f"Entity deletion not allowed on {setNameRep}" if browse: return [[msg]] @@ -3026,7 +3087,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                def fromSourceSet(self):
                     """Loads an annotation set from source.
                @@ -3051,6 +3112,7 @@ 

                Parameters

                settings = self.settings setName = self.setName + setIsSrc = self.setIsSrc setData = self.sets[setName] annoDir = self.annoDir @@ -3071,7 +3133,25 @@

                Parameters

                changed = False - if setName: + if setIsSrc: + if "entities" not in setData: + entities = {} + hasFeature = {feat: checkFeature(feat) for feat in features} + + for e in self.getEntityNodes(): + slots = getSlots(e) + entities[e] = ( + tuple( + getFVal(feat, e) + if hasFeature[feat] + else featureDefault[feat](slots) + for feat in features + ), + tuple(slots), + ) + + setData.entities = entities + else: if ( "entities" not in setData or "dateLoaded" not in setData @@ -3092,24 +3172,6 @@

                Parameters

                setData.entities = entities setData.dateLoaded = time.time() - else: - if "entities" not in setData: - entities = {} - hasFeature = {feat: checkFeature(feat) for feat in features} - - for e in self.getEntityNodes(): - slots = getSlots(e) - entities[e] = ( - tuple( - getFVal(feat, e) - if hasFeature[feat] - else featureDefault[feat](slots) - for feat in features - ), - tuple(slots), - ) - - setData.entities = entities return changed
                @@ -3127,9 +3189,9 @@

                Parameters

                Expand source code -Browse git +Browse git -
                def loadSetData(self):
                +
                def loadSetData(self, _lowlevel=False):
                     """Loads the current annotation set into memory.
                 
                     It has two phases:
                @@ -3166,9 +3228,9 @@ 

                Parameters

                Expand source code -Browse git +Browse git -
                def mergeEntities(self, newEntities):
                +
                def mergeEntities(self, newEntities, _lowlevel=False):
                     """Performs additions to the current annotation set.
                 
                     This operation is not allowed if the current set is the read-only set with the
                @@ -3185,11 +3247,16 @@ 

                Parameters

                setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo + setIsSrc = self.setIsSrc - if not setName: + if not _lowlevel and setIsRo: self.console(f"Entity merging not allowed on {setNameRep}", error=True) return + if _lowlevel and (setIsSrc or not setIsRo): + return + annoDir = self.annoDir dataFile = f"{annoDir}/{setName}/entities.tsv" @@ -3257,7 +3324,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                def processSet(self, changed):
                     """Generates derived data structures out of the source set.
                @@ -3431,7 +3498,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def saveEntitiesAs(self, dataFile):
                     """Export an annotation set to a file.
                @@ -3471,7 +3538,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def weedEntities(self, delEntities):
                     """Performs deletions to the current annotation set.
                @@ -3490,8 +3557,9 @@ 

                Parameters

                setName = self.setName setNameRep = self.setNameRep + setIsRo = self.setIsRo - if not setName: + if setIsRo: self.console(f"Entity weeding not allowed on {setNameRep}", error=True) return diff --git a/tf/browser/ner/form.html b/tf/browser/ner/form.html index a6c27cdb0..c91114955 100644 --- a/tf/browser/ner/form.html +++ b/tf/browser/ner/form.html @@ -37,7 +37,7 @@

                Module tf.browser.ner.form

                Expand source code -Browse git +Browse git
                """Machinery for request reading.
                 
                @@ -170,7 +170,7 @@ 

                Module tf.browser.ner.form

                keysSetInt = self.keysSetInt keysJson = self.keysJson - form = {} + form = AttrDict() for k in keysStr: form[k] = self.fgets(k) @@ -228,7 +228,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                class Form:
                     def __init__(
                @@ -344,7 +344,7 @@ 

                Parameters

                keysSetInt = self.keysSetInt keysJson = self.keysJson - form = {} + form = AttrDict() for k in keysStr: form[k] = self.fgets(k) @@ -383,7 +383,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def fget2(self, k):
                     """Makes form value under key `k` or its default into an boolean."""
                @@ -399,7 +399,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def fget3(self, k):
                     """Makes form value under key `k` or its default into a 3-way boolean."""
                @@ -415,7 +415,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def fgeti(self, k):
                     """Makes form value under key `k` or its default into an integer."""
                @@ -433,7 +433,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def fgetj(self, k):
                     """Makes form value under key `k` or its default into a data structure.
                @@ -457,7 +457,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def fgets(self, k):
                     """Makes form value under key `k` or its default into an string."""
                @@ -476,7 +476,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def fgetsi(self, k):
                     """Makes form value under key `k` or its default into a set.
                @@ -503,7 +503,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def fgettu(self, k):
                     """Makes form value under key `k` or its default into a tuple.
                @@ -530,7 +530,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def fill(self):
                     """Fill a dictionary with interpreted form values.
                @@ -551,7 +551,7 @@ 

                Returns

                keysSetInt = self.keysSetInt keysJson = self.keysJson - form = {} + form = AttrDict() for k in keysStr: form[k] = self.fgets(k) diff --git a/tf/browser/ner/fragments.html b/tf/browser/ner/fragments.html index 7299b3ad1..46b200df6 100644 --- a/tf/browser/ner/fragments.html +++ b/tf/browser/ner/fragments.html @@ -35,7 +35,7 @@

                Module tf.browser.ner.fragments

                Expand source code -Browse git +Browse git
                """Wraps various pieces into HTML.
                 
                @@ -61,8 +61,7 @@ 

                Module tf.browser.ner.fragments

                def wrapSets(self): """HTML for the annotation set chooser. - It is a list of buttons, each corresponding to an existing annotation set. - A click on the button selects that set. + It is a dropdown with options, each corresponding to an existing annotation set. There is also a control to delete the set. Apart from these buttons there is a button to switch to the entities that are @@ -74,8 +73,6 @@

                Module tf.browser.ner.fragments

                """ ner = self.ner setNames = ner.setNames - settings = ner.settings - entitySet = settings.entitySet v = self.v chosenSet = v.set @@ -118,7 +115,7 @@

                Module tf.browser.ner.fragments

                H.select( ( H.option( - entitySet if setName == "" else setName, + ner.setInfo(setName=setName)[0], value=setName, selected=setName == chosenSet, ) @@ -153,12 +150,43 @@

                Module tf.browser.ner.fragments

                cls="mono", ), ] - if chosenSet + if not (chosenSet == "" or chosenSet.startswith(".")) else [] ) v.sets = H.p(content1, content2) + def wrapCaption(self): + v = self.v + ner = self.ner + setNameRep = ner.setNameRep + setIsSrc = ner.setIsSrc + setIsRo = ner.setIsRo + v.caption = H.p(H.b(setNameRep)) + H.p( + "Entities as " + + ( + "given in the source" + if setIsSrc + else "specified by a spreadsheet" + if setIsRo + else "marked up by hand" + ) + ) + + def wrapLogs(self): + v = self.v + ner = self.ner + logData = ner.logData + + v.logs = "\n".join( + H.p( + H.nb * indent + msg, + cls="msg " + + ("special" if isError is None else "error" if isError else "info"), + ) + for (isError, indent, msg) in logData + ) + def wrapQuery(self): """HTML for all control widgets on the page.""" self.wrapAppearance() @@ -533,7 +561,7 @@

                Module tf.browser.ner.fragments

                """ v = self.v ner = self.ner - setName = ner.setName + setIsRo = ner.setIsRo scope = v.scope hasFilter = v.hasfilter txt = v.txt @@ -544,7 +572,7 @@

                Module tf.browser.ner.fragments

                scopeInit = H.input(type="hidden", id="scope", name="scope", value=scope) scopeFilter = "" - if setName and (hasOcc or hasEnt): + if (not setIsRo) and (hasOcc or hasEnt): # Scope of modification scopeFilter = ( @@ -572,13 +600,13 @@

                Module tf.browser.ner.fragments

                ner = self.ner settings = ner.settings bucketType = settings.bucketType - setName = ner.setName + setIsRo = ner.setIsRo hasOcc = txt != "" hasEnt = eTxt != "" scopeExceptions = "" - if setName and (hasOcc or hasEnt): + if (not setIsRo) and (hasOcc or hasEnt): scopeExceptions = H.span( H.nb, H.button( @@ -618,7 +646,7 @@

                Module tf.browser.ner.fragments

                featureDefault = ner.featureDefault setData = ner.getSetData() - setName = ner.setName + setIsRo = ner.setIsRo txt = v.txt eTxt = v.etxt @@ -647,7 +675,7 @@

                Module tf.browser.ner.fragments

                somethingToDelete = True - if setName and (hasOcc or hasEnt): + if (not setIsRo) and (hasOcc or hasEnt): instances = self.wrapExceptions() for i, feat in enumerate(features): @@ -947,7 +975,7 @@

                Classes

                Expand source code -Browse git +Browse git
                class Fragments:
                     def wrapMessages(self):
                @@ -960,8 +988,7 @@ 

                Classes

                def wrapSets(self): """HTML for the annotation set chooser. - It is a list of buttons, each corresponding to an existing annotation set. - A click on the button selects that set. + It is a dropdown with options, each corresponding to an existing annotation set. There is also a control to delete the set. Apart from these buttons there is a button to switch to the entities that are @@ -973,8 +1000,6 @@

                Classes

                """ ner = self.ner setNames = ner.setNames - settings = ner.settings - entitySet = settings.entitySet v = self.v chosenSet = v.set @@ -1017,7 +1042,7 @@

                Classes

                H.select( ( H.option( - entitySet if setName == "" else setName, + ner.setInfo(setName=setName)[0], value=setName, selected=setName == chosenSet, ) @@ -1052,12 +1077,43 @@

                Classes

                cls="mono", ), ] - if chosenSet + if not (chosenSet == "" or chosenSet.startswith(".")) else [] ) v.sets = H.p(content1, content2) + def wrapCaption(self): + v = self.v + ner = self.ner + setNameRep = ner.setNameRep + setIsSrc = ner.setIsSrc + setIsRo = ner.setIsRo + v.caption = H.p(H.b(setNameRep)) + H.p( + "Entities as " + + ( + "given in the source" + if setIsSrc + else "specified by a spreadsheet" + if setIsRo + else "marked up by hand" + ) + ) + + def wrapLogs(self): + v = self.v + ner = self.ner + logData = ner.logData + + v.logs = "\n".join( + H.p( + H.nb * indent + msg, + cls="msg " + + ("special" if isError is None else "error" if isError else "info"), + ) + for (isError, indent, msg) in logData + ) + def wrapQuery(self): """HTML for all control widgets on the page.""" self.wrapAppearance() @@ -1432,7 +1488,7 @@

                Classes

                """ v = self.v ner = self.ner - setName = ner.setName + setIsRo = ner.setIsRo scope = v.scope hasFilter = v.hasfilter txt = v.txt @@ -1443,7 +1499,7 @@

                Classes

                scopeInit = H.input(type="hidden", id="scope", name="scope", value=scope) scopeFilter = "" - if setName and (hasOcc or hasEnt): + if (not setIsRo) and (hasOcc or hasEnt): # Scope of modification scopeFilter = ( @@ -1471,13 +1527,13 @@

                Classes

                ner = self.ner settings = ner.settings bucketType = settings.bucketType - setName = ner.setName + setIsRo = ner.setIsRo hasOcc = txt != "" hasEnt = eTxt != "" scopeExceptions = "" - if setName and (hasOcc or hasEnt): + if (not setIsRo) and (hasOcc or hasEnt): scopeExceptions = H.span( H.nb, H.button( @@ -1517,7 +1573,7 @@

                Classes

                featureDefault = ner.featureDefault setData = ner.getSetData() - setName = ner.setName + setIsRo = ner.setIsRo txt = v.txt eTxt = v.etxt @@ -1546,7 +1602,7 @@

                Classes

                somethingToDelete = True - if setName and (hasOcc or hasEnt): + if (not setIsRo) and (hasOcc or hasEnt): instances = self.wrapExceptions() for i, feat in enumerate(features): @@ -1842,7 +1898,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def wrapActive(self):
                     """HTML for the active entity."""
                @@ -1871,7 +1927,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def wrapAppearance(self):
                     """HTML for the appearance widget.
                @@ -1933,6 +1989,34 @@ 

                Methods

                )
                +
                +def wrapCaption(self) +
                +
                +
                +
                + +Expand source code +Browse git + +
                def wrapCaption(self):
                +    v = self.v
                +    ner = self.ner
                +    setNameRep = ner.setNameRep
                +    setIsSrc = ner.setIsSrc
                +    setIsRo = ner.setIsRo
                +    v.caption = H.p(H.b(setNameRep)) + H.p(
                +        "Entities as "
                +        + (
                +            "given in the source"
                +            if setIsSrc
                +            else "specified by a spreadsheet"
                +            if setIsRo
                +            else "marked up by hand"
                +        )
                +    )
                +
                +
                def wrapEntity(self)
                @@ -1944,7 +2028,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def wrapEntity(self):
                     """Basic data for the selected entity widget.
                @@ -2012,7 +2096,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def wrapEntityFeats(self):
                     """HTML for the entity feature value selection.
                @@ -2113,7 +2197,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def wrapEntityHeaders(self):
                     """HTML for the header of the entity table, dependent on the state of sorting."""
                @@ -2160,7 +2244,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def wrapEntityModReport(self):
                     """HTML for the combined report of add / del actions."""
                @@ -2185,7 +2269,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def wrapEntityModify(self):
                     """HTML for the add / del widget.
                @@ -2205,7 +2289,7 @@ 

                Methods

                featureDefault = ner.featureDefault setData = ner.getSetData() - setName = ner.setName + setIsRo = ner.setIsRo txt = v.txt eTxt = v.etxt @@ -2234,7 +2318,7 @@

                Methods

                somethingToDelete = True - if setName and (hasOcc or hasEnt): + if (not setIsRo) and (hasOcc or hasEnt): instances = self.wrapExceptions() for i, feat in enumerate(features): @@ -2443,7 +2527,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def wrapEntityStat(self, val, feat):
                     """HTML for statistics of feature values.
                @@ -2476,7 +2560,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def wrapEntityText(self):
                     """HTML for the selected entity widget."""
                @@ -2533,7 +2617,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def wrapExceptions(self):
                     """HTML for the select / deselect buttons.
                @@ -2549,13 +2633,13 @@ 

                Methods

                ner = self.ner settings = ner.settings bucketType = settings.bucketType - setName = ner.setName + setIsRo = ner.setIsRo hasOcc = txt != "" hasEnt = eTxt != "" scopeExceptions = "" - if setName and (hasOcc or hasEnt): + if (not setIsRo) and (hasOcc or hasEnt): scopeExceptions = H.span( H.nb, H.button( @@ -2589,7 +2673,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def wrapFilter(self):
                     """HTML for the filter widget.
                @@ -2676,7 +2760,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def wrapFindStat(self):
                     """HTML for statistics.
                @@ -2693,6 +2777,31 @@ 

                Methods

                return H.span(n, cls="stat")
                +
                +def wrapLogs(self) +
                +
                +
                +
                + +Expand source code +Browse git + +
                def wrapLogs(self):
                +    v = self.v
                +    ner = self.ner
                +    logData = ner.logData
                +
                +    v.logs = "\n".join(
                +        H.p(
                +            H.nb * indent + msg,
                +            cls="msg "
                +            + ("special" if isError is None else "error" if isError else "info"),
                +        )
                +        for (isError, indent, msg) in logData
                +    )
                +
                +
                def wrapMessages(self)
                @@ -2701,7 +2810,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def wrapMessages(self):
                     """HTML for messages."""
                @@ -2719,7 +2828,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def wrapQuery(self):
                     """HTML for all control widgets on the page."""
                @@ -2741,7 +2850,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def wrapReport(self, report, kind):
                     """HTML for the report of add / del actions."""
                @@ -2776,7 +2885,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def wrapScope(self):
                     """HTML for the scope widget.
                @@ -2786,7 +2895,7 @@ 

                Methods

                """ v = self.v ner = self.ner - setName = ner.setName + setIsRo = ner.setIsRo scope = v.scope hasFilter = v.hasfilter txt = v.txt @@ -2797,7 +2906,7 @@

                Methods

                scopeInit = H.input(type="hidden", id="scope", name="scope", value=scope) scopeFilter = "" - if setName and (hasOcc or hasEnt): + if (not setIsRo) and (hasOcc or hasEnt): # Scope of modification scopeFilter = ( @@ -2817,8 +2926,7 @@

                Methods

                HTML for the annotation set chooser.

                -

                It is a list of buttons, each corresponding to an existing annotation set. -A click on the button selects that set. +

                It is a dropdown with options, each corresponding to an existing annotation set. There is also a control to delete the set.

                Apart from these buttons there is a button to switch to the entities that are present in the TF dataset as nodes of the entity type specified @@ -2828,13 +2936,12 @@

                Methods

                Expand source code -Browse git +Browse git
                def wrapSets(self):
                     """HTML for the annotation set chooser.
                 
                -    It is a list of buttons, each corresponding to an existing annotation set.
                -    A click on the button selects that set.
                +    It is a dropdown with options, each corresponding to an existing annotation set.
                     There is also a control to delete the set.
                 
                     Apart from these buttons there is a button to switch to the entities that are
                @@ -2846,8 +2953,6 @@ 

                Methods

                """ ner = self.ner setNames = ner.setNames - settings = ner.settings - entitySet = settings.entitySet v = self.v chosenSet = v.set @@ -2890,7 +2995,7 @@

                Methods

                H.select( ( H.option( - entitySet if setName == "" else setName, + ner.setInfo(setName=setName)[0], value=setName, selected=setName == chosenSet, ) @@ -2925,7 +3030,7 @@

                Methods

                cls="mono", ), ] - if chosenSet + if not (chosenSet == "" or chosenSet.startswith(".")) else [] ) @@ -3006,6 +3111,7 @@

              • wrapActive
              • wrapAppearance
              • +
              • wrapCaption
              • wrapEntity
              • wrapEntityFeats
              • wrapEntityHeaders
              • @@ -3016,6 +3122,7 @@

                wrapExceptions
              • wrapFilter
              • wrapFindStat
              • +
              • wrapLogs
              • wrapMessages
              • wrapQuery
              • wrapReport
              • diff --git a/tf/browser/ner/helpers.html b/tf/browser/ner/helpers.html index c5103656c..379940d6c 100644 --- a/tf/browser/ner/helpers.html +++ b/tf/browser/ner/helpers.html @@ -35,7 +35,7 @@

                Module tf.browser.ner.helpers

                Expand source code -Browse git +Browse git
                """Auxiliary functions.
                 
                @@ -49,7 +49,6 @@ 

                Module tf.browser.ner.helpers

                from ...core.helpers import console from ..html import H - from .settings import STYLES @@ -319,9 +318,22 @@

                Module tf.browser.ner.helpers

                return () -def log(rh, msg, error=False): - console(msg, error=error) - rh.write(f"{msg}\n")
                +def consoleLine(isError, indent, msg): + tabs = " " * indent + head = "-" * len(msg) + + if isError is None: + console("") + console(f"{tabs}{head}") + + console(f"{tabs}{msg}\n", error=isError) + + if isError is None: + console(f"{tabs}{head}") + + +def repSet(s): + return "{" + ", ".join(str(x) for x in sorted(s)) + "}"

                @@ -346,6 +358,30 @@

                Global variables

                Functions

                +
                +def consoleLine(isError, indent, msg) +
                +
                +
                +
                + +Expand source code +Browse git + +
                def consoleLine(isError, indent, msg):
                +    tabs = "  " * indent
                +    head = "-" * len(msg)
                +
                +    if isError is None:
                +        console("")
                +        console(f"{tabs}{head}")
                +
                +    console(f"{tabs}{msg}\n", error=isError)
                +
                +    if isError is None:
                +        console(f"{tabs}{head}")
                +
                +
                def findCompile(bFind, bFindC)
                @@ -368,7 +404,7 @@

                Returns

                Expand source code -Browse git +Browse git
                def findCompile(bFind, bFindC):
                     """Compiles a regular expression out of a search pattern.
                @@ -414,7 +450,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def fromTokens(tokens, spaceEscaped=False):
                     """The inverse of `toTokens()`.
                @@ -438,7 +474,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def getPath(heading, instructions):
                     for n in range(len(heading), 0, -1):
                @@ -450,21 +486,6 @@ 

                Returns

                return ()
                -
                -def log(rh, msg, error=False) -
                -
                -
                -
                - -Expand source code -Browse git - -
                def log(rh, msg, error=False):
                -    console(msg, error=error)
                -    rh.write(f"{msg}\n")
                -
                -
                def makeCss(features, keywordFeatures)
                @@ -482,7 +503,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                def makeCss(features, keywordFeatures):
                     """Generates CSS for the tool.
                @@ -551,7 +572,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def normalize(text):
                     """Normalize white-space in a text."""
                @@ -574,7 +595,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def repIdent(features, vals, active=""):
                     """Represents an identifier in HTML.
                @@ -593,6 +614,20 @@ 

                Parameters

                )
                +
                +def repSet(s) +
                +
                +
                +
                + +Expand source code +Browse git + +
                def repSet(s):
                +    return "{" + ", ".join(str(x) for x in sorted(s)) + "}"
                +
                +
                def repSummary(keywordFeatures, vals, active='')
                @@ -609,7 +644,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                def repSummary(keywordFeatures, vals, active=""):
                     """Represents an keyword value in HTML.
                @@ -639,7 +674,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def tnorm(text, spaceEscaped=False):
                     return fromTokens(
                @@ -659,7 +694,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def toAscii(text):
                     """Transforms a text with diacritical marks into a plain ASCII text.
                @@ -685,7 +720,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def toId(text):
                     """Transforms text to an identifier string.
                @@ -708,7 +743,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def toSmallId(text, transform={}):
                     """Transforms text to a smaller identifier string.
                @@ -755,7 +790,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def toTokens(text, spaceEscaped=False):
                     """Split a text into tokens.
                @@ -782,7 +817,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def valRep(features, fVals):
                     """HTML representation of an entity as a sequence of `feat=val` strings."""
                @@ -865,13 +900,14 @@ 

                Index

              • Functions

                  +
                • consoleLine
                • findCompile
                • fromTokens
                • getPath
                • -
                • log
                • makeCss
                • normalize
                • repIdent
                • +
                • repSet
                • repSummary
                • tnorm
                • toAscii
                • diff --git a/tf/browser/ner/match.html b/tf/browser/ner/match.html index a3bac2ae6..9f776bc83 100644 --- a/tf/browser/ner/match.html +++ b/tf/browser/ner/match.html @@ -34,7 +34,7 @@

                  Module tf.browser.ner.match

                  Expand source code -Browse git +Browse git
                  """Match functions.
                   
                  @@ -42,6 +42,7 @@ 

                  Module tf.browser.ner.match

                  `tf.browser.ner.ner` . """ +from ...core.generic import AttrDict from .settings import NONE from .helpers import getPath, fromTokens @@ -84,9 +85,9 @@

                  Module tf.browser.ner.match

                  heading = getHeadings(b) path = getPath(heading, instructions) data = instructions[path] - tPos = data["tPos"] - tMap = data["tMap"] - idMap = data["idMap"] + tPos = data.tPos + tMap = data.tMap + idMap = data.idMap # compile the bucket into logical tokens bTokensAll = getTokens(b) @@ -146,7 +147,9 @@

                  Module tf.browser.ner.match

                  lastT = bStringLast[i + m] slots = tuple(range(firstT, lastT + 1)) eidkind = idMap[trigger] - dest = results.setdefault(eidkind, {}).setdefault(trigger, {}) + dest = results.setdefault(eidkind, AttrDict()).setdefault( + trigger, {} + ) destHits = dest.setdefault(tPath, []) destHits.append(slots) break @@ -157,61 +160,6 @@

                  Module tf.browser.ner.match

                  return results -def occMatchOld(getTokens, b, qSeqs, results): - """Finds the occurrences of multiple sequences of tokens in a single bucket. - - Parameters - ---------- - getTokens: function - See `tf.browser.ner.corpus.Corpus.getTokens` - b: integer - The node of the bucket in question - qSeqs: set, optional set() - A set of sequences of tokens. Each sequence in the set will be used as a - search pattern, and it occurrences in the bucket are collected. - result: dict - A dictionary to collect the results in. - Keyed by each member of parameter `qSeqs` the values are - the occurrences of that member in the corpus. - A single occurrence is represented as a tuple of slots. - """ - bTokensAll = getTokens(b) - bTokens = [x for x in bTokensAll if (x[1] or "").strip()] - # bStrings = {s for (t, s) in bTokens} - bStrings = [] - bStringFirst = {} - bStringLast = {} - - for t, s in bTokens: - if len(bStrings) > 1 and bStrings[-1] == "-": - bStrings.pop() - bStrings[-1] += s - bStringLast[len(bStrings) - 1] = t - else: - bStrings.append(s) - bStringFirst[len(bStrings) - 1] = t - bStringLast[len(bStrings) - 1] = t - - bStrings = tuple(bStrings) - bStringSet = set(bStrings) - - for qTokens in qSeqs: - if any(s not in bStringSet for s in qTokens): - continue - - nTokens = len(qTokens) - - for i, s in enumerate(bStrings): - if qTokens != bStrings[i : i + nTokens]: - continue - - firstT = bStringFirst[i] - lastT = bStringLast[i + nTokens - 1] - slots = tuple(range(firstT, lastT + 1)) - - results.setdefault(qTokens, []).append(slots) - - def entityMatch( entityIndex, eStarts, @@ -449,7 +397,7 @@

                  Returns

                  Expand source code -Browse git +Browse git
                  def entityMatch(
                       entityIndex,
                  @@ -669,7 +617,7 @@ 

                  Parameters

                  Expand source code -Browse git +Browse git
                  def occMatch(getTokens, getHeadings, buckets, instructions, spaceEscaped):
                       """Finds the occurrences of multiple sequences of tokens in a single bucket.
                  @@ -709,9 +657,9 @@ 

                  Parameters

                  heading = getHeadings(b) path = getPath(heading, instructions) data = instructions[path] - tPos = data["tPos"] - tMap = data["tMap"] - idMap = data["idMap"] + tPos = data.tPos + tMap = data.tMap + idMap = data.idMap # compile the bucket into logical tokens bTokensAll = getTokens(b) @@ -771,7 +719,9 @@

                  Parameters

                  lastT = bStringLast[i + m] slots = tuple(range(firstT, lastT + 1)) eidkind = idMap[trigger] - dest = results.setdefault(eidkind, {}).setdefault(trigger, {}) + dest = results.setdefault(eidkind, AttrDict()).setdefault( + trigger, {} + ) destHits = dest.setdefault(tPath, []) destHits.append(slots) break @@ -782,86 +732,6 @@

                  Parameters

                  return results
                  -
                  -def occMatchOld(getTokens, b, qSeqs, results) -
                  -
                  -

                  Finds the occurrences of multiple sequences of tokens in a single bucket.

                  -

                  Parameters

                  -
                  -
                  getTokens : function
                  -
                  See Corpus.getTokens
                  -
                  b : integer
                  -
                  The node of the bucket in question
                  -
                  qSeqs : set, optional set()
                  -
                  A set of sequences of tokens. Each sequence in the set will be used as a -search pattern, and it occurrences in the bucket are collected.
                  -
                  result : dict
                  -
                  A dictionary to collect the results in. -Keyed by each member of parameter qSeqs the values are -the occurrences of that member in the corpus. -A single occurrence is represented as a tuple of slots.
                  -
                  -
                  - -Expand source code -Browse git - -
                  def occMatchOld(getTokens, b, qSeqs, results):
                  -    """Finds the occurrences of multiple sequences of tokens in a single bucket.
                  -
                  -    Parameters
                  -    ----------
                  -    getTokens: function
                  -        See `tf.browser.ner.corpus.Corpus.getTokens`
                  -    b: integer
                  -        The node of the bucket in question
                  -    qSeqs: set, optional set()
                  -        A set of sequences of tokens. Each sequence in the set will be used as a
                  -        search pattern, and it occurrences in the bucket are collected.
                  -    result: dict
                  -        A dictionary to collect the results in.
                  -        Keyed by each member of parameter `qSeqs` the values are
                  -        the occurrences of that member in the corpus.
                  -        A single occurrence is represented as a tuple of slots.
                  -    """
                  -    bTokensAll = getTokens(b)
                  -    bTokens = [x for x in bTokensAll if (x[1] or "").strip()]
                  -    # bStrings = {s for (t, s) in bTokens}
                  -    bStrings = []
                  -    bStringFirst = {}
                  -    bStringLast = {}
                  -
                  -    for t, s in bTokens:
                  -        if len(bStrings) > 1 and bStrings[-1] == "-":
                  -            bStrings.pop()
                  -            bStrings[-1] += s
                  -            bStringLast[len(bStrings) - 1] = t
                  -        else:
                  -            bStrings.append(s)
                  -            bStringFirst[len(bStrings) - 1] = t
                  -            bStringLast[len(bStrings) - 1] = t
                  -
                  -    bStrings = tuple(bStrings)
                  -    bStringSet = set(bStrings)
                  -
                  -    for qTokens in qSeqs:
                  -        if any(s not in bStringSet for s in qTokens):
                  -            continue
                  -
                  -        nTokens = len(qTokens)
                  -
                  -        for i, s in enumerate(bStrings):
                  -            if qTokens != bStrings[i : i + nTokens]:
                  -                continue
                  -
                  -            firstT = bStringFirst[i]
                  -            lastT = bStringLast[i + nTokens - 1]
                  -            slots = tuple(range(firstT, lastT + 1))
                  -
                  -            results.setdefault(qTokens, []).append(slots)
                  -
                  -
              • @@ -933,7 +803,6 @@

                Index

              diff --git a/tf/browser/ner/ner.html b/tf/browser/ner/ner.html index 99d5aeb24..e24c321b9 100644 --- a/tf/browser/ner/ner.html +++ b/tf/browser/ner/ner.html @@ -188,8 +188,7 @@

              The entity spreadsheets

              Inventory

              A first step is to find out how many occurrences we find in the corpus for these surface forms:

              -
              NE.lookup()
              -NE.showHits()
              +
              NE.reportHits()
               

              and the output looks like this

              ...
              @@ -206,21 +205,6 @@ 

              Inventory

              Total 150

              Entities that are in the spreadsheet, but not in the corpus are skipped.

              -

              Marking up

              -

              In order to create annotations for these entities, we have to switch to an -annotation set. Let's start a new set and give it the name power.

              -
              NE.setSet("power")
              -
              -

              If it turns out that power has already annotations, and you want to clear them, say

              -
              NE.resetSet("power")
              -
              -

              Now we are ready for the big thing: creating the annotations:

              -
              NE.markEntities()
              -
              -

              It outputs this message:

              -
              Already present:     0 x
              -Added:             150 x
              -

              Inspection

              We now revert to lower-level methods from the tf.browser.ner.ner class to inspect some of the results.

              @@ -260,7 +244,7 @@

              Inspection

              Expand source code -Browse git +Browse git
              """API for Named Entity marking.
               
              @@ -455,8 +439,7 @@ 

              Inspection

              surface forms: ``` python -NE.lookup() -NE.showHits() +NE.reportHits() ``` and the output looks like this @@ -478,34 +461,6 @@

              Inspection

              Entities that are in the spreadsheet, but not in the corpus are skipped. -## Marking up - -In order to create annotations for these entities, we have to switch to an -annotation set. Let's start a new set and give it the name `power`. - -``` python -NE.setSet("power") -``` - -If it turns out that `power` has already annotations, and you want to clear them, say - -``` python -NE.resetSet("power") -``` - -Now we are ready for the big thing: creating the annotations: - -``` python -NE.markEntities() -``` - -It outputs this message: - -``` -Already present: 0 x -Added: 150 x -``` - ## Inspection We now revert to lower-level methods from the `tf.browser.ner.ner` class to @@ -938,15 +893,16 @@

              Inspection

              inventory = sheetData.inventory instructions = sheetData.instructions - reportBase = self.reportBase - reportDir = f"{reportBase}/{sheetName}" - reportFile = f"{reportDir}/hits.tsv" + setName = self.setName + annoDir = self.annoDir + setDir = f"{annoDir}/{setName}" + reportFile = f"{setDir}/hits.tsv" allTriggers = set() for path, data in instructions.items(): - idMap = data["idMap"] - tMap = data["tMap"] + idMap = data.idMap + tMap = data.tMap for trigger, tPath in tMap.items(): eidkind = idMap[trigger] @@ -1020,40 +976,6 @@

              Inspection

              ) ) - def markEntities(self): - """Marks up the members of the inventory as entities. - - The instructions contain the entity identifier and the entity kind that - have to be assigned to the surface forms. - - The inventory knows where the occurrences of the surface forms are. - If there is no inventory yet, it will be created. - """ - if not self.properlySetup: - return - - browse = self.browse - sheetName = self.sheetName - sheetData = self.sheets[sheetName] - inventory = sheetData.inventory - - newEntities = [] - - for (eidkind, entData) in inventory.items(): - for (trigger, triggerData) in entData.items(): - for matches in triggerData.values(): - newEntities.append((eidkind, matches)) - - self.setSet(sheetName) - - if self.getSetData(): - if not browse: - console(f"Set {sheetName} already exists. I will not overwrite it.") - console("Clear or delete this set before marking the entities") - return - - self.addEntities(newEntities, silent=False) - def bakeEntities(self, versionExtension="e"): """Bakes the entities of the current set as nodes into a new TF data source. @@ -1115,7 +1037,7 @@

              Parameters

              Expand source code -Browse git +Browse git
              class NER(Sheets, Sets, Show):
                   def __init__(self, app, data=None, browse=False):
              @@ -1488,15 +1410,16 @@ 

              Parameters

              inventory = sheetData.inventory instructions = sheetData.instructions - reportBase = self.reportBase - reportDir = f"{reportBase}/{sheetName}" - reportFile = f"{reportDir}/hits.tsv" + setName = self.setName + annoDir = self.annoDir + setDir = f"{annoDir}/{setName}" + reportFile = f"{setDir}/hits.tsv" allTriggers = set() for path, data in instructions.items(): - idMap = data["idMap"] - tMap = data["tMap"] + idMap = data.idMap + tMap = data.tMap for trigger, tPath in tMap.items(): eidkind = idMap[trigger] @@ -1570,40 +1493,6 @@

              Parameters

              ) ) - def markEntities(self): - """Marks up the members of the inventory as entities. - - The instructions contain the entity identifier and the entity kind that - have to be assigned to the surface forms. - - The inventory knows where the occurrences of the surface forms are. - If there is no inventory yet, it will be created. - """ - if not self.properlySetup: - return - - browse = self.browse - sheetName = self.sheetName - sheetData = self.sheets[sheetName] - inventory = sheetData.inventory - - newEntities = [] - - for (eidkind, entData) in inventory.items(): - for (trigger, triggerData) in entData.items(): - for matches in triggerData.values(): - newEntities.append((eidkind, matches)) - - self.setSet(sheetName) - - if self.getSetData(): - if not browse: - console(f"Set {sheetName} already exists. I will not overwrite it.") - console("Clear or delete this set before marking the entities") - return - - self.addEntities(newEntities, silent=False) - def bakeEntities(self, versionExtension="e"): """Bakes the entities of the current set as nodes into a new TF data source. @@ -1640,7 +1529,7 @@

              Parameters

              Expand source code -Browse git +Browse git
              def bakeEntities(self, versionExtension="e"):
                   """Bakes the entities of the current set as nodes into a new TF data source.
              @@ -1748,7 +1637,7 @@ 

              Returns

              Expand source code -Browse git +Browse git
              def filterContent(
                   self,
              @@ -2011,7 +1900,7 @@ 

              Returns

              Expand source code -Browse git +Browse git
              def findOccs(self):
                   """Finds the occurrences of multiple triggers.
              @@ -2067,7 +1956,7 @@ 

              Returns

              Expand source code -Browse git +Browse git
              def lookup(self):
                   """Explores the corpus for the surface forms mentioned in the instructions.
              @@ -2086,55 +1975,6 @@ 

              Returns

              self.processSheet(True)
              -
              -def markEntities(self) -
              -
              -

              Marks up the members of the inventory as entities.

              -

              The instructions contain the entity identifier and the entity kind that -have to be assigned to the surface forms.

              -

              The inventory knows where the occurrences of the surface forms are. -If there is no inventory yet, it will be created.

              -
              - -Expand source code -Browse git - -
              def markEntities(self):
              -    """Marks up the members of the inventory as entities.
              -
              -    The instructions contain the entity identifier and the entity kind that
              -    have to be assigned to the surface forms.
              -
              -    The inventory knows where the occurrences of the surface forms are.
              -    If there is no inventory yet, it will be created.
              -    """
              -    if not self.properlySetup:
              -        return
              -
              -    browse = self.browse
              -    sheetName = self.sheetName
              -    sheetData = self.sheets[sheetName]
              -    inventory = sheetData.inventory
              -
              -    newEntities = []
              -
              -    for (eidkind, entData) in inventory.items():
              -        for (trigger, triggerData) in entData.items():
              -            for matches in triggerData.values():
              -                newEntities.append((eidkind, matches))
              -
              -    self.setSet(sheetName)
              -
              -    if self.getSetData():
              -        if not browse:
              -            console(f"Set {sheetName} already exists. I will not overwrite it.")
              -            console("Clear or delete this set before marking the entities")
              -        return
              -
              -    self.addEntities(newEntities, silent=False)
              -
              -
              def reportHits(self)
              @@ -2143,7 +1983,7 @@

              Returns

              Expand source code -Browse git +Browse git
              def reportHits(self):
                   """Reports the inventory."""
              @@ -2158,15 +1998,16 @@ 

              Returns

              inventory = sheetData.inventory instructions = sheetData.instructions - reportBase = self.reportBase - reportDir = f"{reportBase}/{sheetName}" - reportFile = f"{reportDir}/hits.tsv" + setName = self.setName + annoDir = self.annoDir + setDir = f"{annoDir}/{setName}" + reportFile = f"{setDir}/hits.tsv" allTriggers = set() for path, data in instructions.items(): - idMap = data["idMap"] - tMap = data["tMap"] + idMap = data.idMap + tMap = data.tMap for trigger, tPath in tMap.items(): eidkind = idMap[trigger] @@ -2297,7 +2138,6 @@

              Inherited members

            • setDup
            • setMove
            • setName
            • -
            • setNameRep
            • setNames
            • setSet
            • slotType
            • @@ -2375,7 +2215,6 @@

              Index

            • Starting up
            • The entity spreadsheets
            • Inventory
            • -
            • Marking up
            • Inspection
          • @@ -2391,12 +2230,11 @@

            Index

            • NER

              -
                + diff --git a/tf/browser/ner/request.html b/tf/browser/ner/request.html index cd13aa2e7..e616db806 100644 --- a/tf/browser/ner/request.html +++ b/tf/browser/ner/request.html @@ -34,7 +34,7 @@

                Module tf.browser.ner.request

                Expand source code -Browse git +Browse git
                """Auxiliary functions for managing request data.
                 
                @@ -89,6 +89,8 @@ 

                Module tf.browser.ner.request

                duset rset dset + caption + logs sortkey sortdir bfind @@ -157,7 +159,8 @@

                Module tf.browser.ner.request

                for feat, featStr in valSelectProto.items(): keysStr.append(featStr) - super().__init__( + Form.__init__( + self, features, defaults, keysStr=keysStr, @@ -200,11 +203,11 @@

                Module tf.browser.ner.request

                form = self.fill() - form["formattingstate"] = { + form.formattingstate = { feat: self.fget2(featStr) for (feat, featStr) in formattingState.items() } - form["activeval"] = { + form.activeval = { feat: self.fgets(featStr) for (feat, featStr) in activeVal.items() } @@ -212,7 +215,7 @@

                Module tf.browser.ner.request

                feat: self.fgets(featStr) for (feat, featStr) in valSelectProto.items() } - submitter = form["submitter"] + submitter = form.submitter valSelect = {} @@ -228,7 +231,7 @@

                Module tf.browser.ner.request

                if startSearch: valSelect[feat].add(NONE) - form["valselect"] = valSelect + form.valselect = valSelect return form @@ -256,7 +259,7 @@

                Module tf.browser.ner.request

                slotType = ner.slotType form = self.getFormData() - resetForm = form["resetForm"] + resetForm = form.resetForm v = AttrDict() v.toolkey = TOOLKEY @@ -375,7 +378,7 @@

                Classes

                Expand source code -Browse git +Browse git
                class Request(Form):
                     def __init__(self):
                @@ -417,6 +420,8 @@ 

                Classes

                duset rset dset + caption + logs sortkey sortdir bfind @@ -485,7 +490,8 @@

                Classes

                for feat, featStr in valSelectProto.items(): keysStr.append(featStr) - super().__init__( + Form.__init__( + self, features, defaults, keysStr=keysStr, @@ -528,11 +534,11 @@

                Classes

                form = self.fill() - form["formattingstate"] = { + form.formattingstate = { feat: self.fget2(featStr) for (feat, featStr) in formattingState.items() } - form["activeval"] = { + form.activeval = { feat: self.fgets(featStr) for (feat, featStr) in activeVal.items() } @@ -540,7 +546,7 @@

                Classes

                feat: self.fgets(featStr) for (feat, featStr) in valSelectProto.items() } - submitter = form["submitter"] + submitter = form.submitter valSelect = {} @@ -556,7 +562,7 @@

                Classes

                if startSearch: valSelect[feat].add(NONE) - form["valselect"] = valSelect + form.valselect = valSelect return form @@ -584,7 +590,7 @@

                Classes

                slotType = ner.slotType form = self.getFormData() - resetForm = form["resetForm"] + resetForm = form.resetForm v = AttrDict() v.toolkey = TOOLKEY @@ -693,7 +699,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                def adaptValSelect(self):
                     """Adapts the values contained in `valSelect` after a modification action.
                @@ -754,7 +760,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def findSetup(self):
                     """Compiles the filter pattern into a regular expression.
                @@ -803,7 +809,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def getFormData(self):
                     """Get form data.
                @@ -836,11 +842,11 @@ 

                Parameters

                form = self.fill() - form["formattingstate"] = { + form.formattingstate = { feat: self.fget2(featStr) for (feat, featStr) in formattingState.items() } - form["activeval"] = { + form.activeval = { feat: self.fgets(featStr) for (feat, featStr) in activeVal.items() } @@ -848,7 +854,7 @@

                Parameters

                feat: self.fgets(featStr) for (feat, featStr) in valSelectProto.items() } - submitter = form["submitter"] + submitter = form.submitter valSelect = {} @@ -864,7 +870,7 @@

                Parameters

                if startSearch: valSelect[feat].add(NONE) - form["valselect"] = valSelect + form.valselect = valSelect return form
                @@ -885,7 +891,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                def initVars(self):
                     """Initializes the computation of the new page.
                @@ -911,7 +917,7 @@ 

                Parameters

                slotType = ner.slotType form = self.getFormData() - resetForm = form["resetForm"] + resetForm = form.resetForm v = AttrDict() v.toolkey = TOOLKEY diff --git a/tf/browser/ner/serve.html b/tf/browser/ner/serve.html index 0194dacd9..d059006e6 100644 --- a/tf/browser/ner/serve.html +++ b/tf/browser/ner/serve.html @@ -36,7 +36,7 @@

                Module tf.browser.ner.serve

                Expand source code -Browse git +Browse git
                """Main controller for Flask
                 
                @@ -72,7 +72,7 @@ 

                Module tf.browser.ner.serve

                ner = web.ner self.ner = ner - super().__init__() + Request.__init__(self) self.initVars() @@ -82,7 +82,7 @@

                Module tf.browser.ner.serve

                ner.setSet(setName) ner.loadSetData() - ner.setSheet(None) + ner.setSheet(setName[1:] if ner.setIsRo and not ner.setIsSrc else None) ner.loadSheetData() def setupFull(self): @@ -294,6 +294,8 @@

                Module tf.browser.ner.serve

                self.wrapSets() self.wrapMessages() + self.wrapCaption() + self.wrapLogs() def updateHandling(self): """Carries out modification actions in the current annotation set. @@ -408,7 +410,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                def serveNer(web):
                     """Main controller to render a full page.
                @@ -440,7 +442,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def serveNerContext(web, node):
                     """Controller to render a portion of a page.
                @@ -482,7 +484,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                class Serve(Request, Fragments):
                     def __init__(self, web):
                @@ -502,7 +504,7 @@ 

                Parameters

                ner = web.ner self.ner = ner - super().__init__() + Request.__init__(self) self.initVars() @@ -512,7 +514,7 @@

                Parameters

                ner.setSet(setName) ner.loadSetData() - ner.setSheet(None) + ner.setSheet(setName[1:] if ner.setIsRo and not ner.setIsSrc else None) ner.loadSheetData() def setupFull(self): @@ -724,6 +726,8 @@

                Parameters

                self.wrapSets() self.wrapMessages() + self.wrapCaption() + self.wrapLogs() def updateHandling(self): """Carries out modification actions in the current annotation set. @@ -806,7 +810,7 @@

                Methods

                Expand source code -Browse git +Browse git
                def actionsFull(self):
                     """Carries out requested actions before building the full page.
                @@ -832,7 +836,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def actionsLean(self, node):
                     """Carries out requested actions before building a portion of the page.
                @@ -874,7 +878,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def getBuckets(self, noFind=False, node=None):
                     """Fetch a selection of buckets from the corpus.
                @@ -962,7 +966,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def setHandling(self):
                     """Carries out the set-related actions before composing the page.
                @@ -1011,7 +1015,9 @@ 

                Parameters

                ner.setSet(chosenSet) self.wrapSets() - self.wrapMessages()
                + self.wrapMessages() + self.wrapCaption() + self.wrapLogs()
                @@ -1027,7 +1033,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                def setupFull(self):
                     """Prepares to serve a complete page.
                @@ -1056,7 +1062,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def setupLean(self):
                     """Prepares to update a portion of the page.
                @@ -1081,7 +1087,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def updateHandling(self):
                     """Carries out modification actions in the current annotation set.
                @@ -1154,7 +1160,7 @@ 

                Parameters

                Expand source code -Browse git +Browse git
                def wrapFull(self):
                     """Builds the full page.
                @@ -1200,7 +1206,7 @@ 

                Returns

                Expand source code -Browse git +Browse git
                def wrapLean(self):
                     """Builds a portion of the page.
                diff --git a/tf/browser/ner/sets.html b/tf/browser/ner/sets.html
                index b312295db..4c8c2d6a2 100644
                --- a/tf/browser/ner/sets.html
                +++ b/tf/browser/ner/sets.html
                @@ -36,7 +36,7 @@ 

                Module tf.browser.ner.sets

                Expand source code -Browse git +Browse git
                """Annotation set management.
                 
                @@ -71,10 +71,18 @@ 

                Module tf.browser.ner.sets

                Annotation sets have names, given by the user. - There is one special annotation set, whose name is the empty string, + There is a special annotation set, whose name is the empty string, and whose content are the pre-existing entities, i.e. the entities that are present in the TF data as nodes and features. + Users can not name sets with names that start with a dot. + + Annotation sets whose name start with a dot are generated by the system + when a family of spreadsheets with entity triggers is processed. + These sets are readonly, like the special annotation set, but they can + be duplicated to ordinary sets. Those copies loose the relationship with + the original spreadsheet. + There is always one current annotation set, whose data is loaded into memory. @@ -84,19 +92,17 @@

                Module tf.browser.ner.sets

                Entity sets to start with. If None, a fresh store of sets will be created by a parent class (Data). """ - super().__init__(sets=sets) + Data.__init__(self, sets=sets) + if not self.properlySetup: return browse = self.browse - settings = self.settings - entitySet = settings.entitySet self.setName = "" """The current annotation set.""" - self.setNameRep = entitySet - """The name representation of the current annotation set.""" + self.setInfo() self.setNames = set() """The set of names of annotation sets that are present on the file system.""" @@ -106,6 +112,33 @@

                Module tf.browser.ner.sets

                if not browse: self.loadSetData() + def setInfo(self, setName=None): + settings = self.settings + entitySet = settings.entitySet + + inObject = False + + if setName is None: + setName = self.setName + inObject = True + + setIsRo = setName == "" or setName.startswith(".") + setIsSrc = setName == "" + + setNameRep = ( + f"🟰 {entitySet}" + if setName == "" + else f"🧾 {setName[1:]}" + if setName.startswith(".") + else f"🖍️ {setName}" + ) + if inObject: + self.setNameRep = setNameRep + self.setIsRo = setIsRo + self.setIsSrc = setIsSrc + else: + return (setNameRep, setIsRo, setIsSrc) + def readSets(self): """Read the list current annotation sets (again). @@ -116,8 +149,7 @@

                Module tf.browser.ner.sets

                self.setNames = set(dirContents(annoDir)[1]) def getSetData(self): - """Deliver the current set. - """ + """Deliver the current set.""" setsData = self.sets setName = self.setName setData = setsData.setdefault(setName, AttrDict()) @@ -137,8 +169,6 @@

                Module tf.browser.ner.sets

                if not self.properlySetup: return - settings = self.settings - entitySet = settings.entitySet browse = self.browse if not browse: @@ -150,14 +180,16 @@

                Module tf.browser.ner.sets

                annoDir = self.annoDir newSetDir = f"{annoDir}/{newSetName}" - if newSetName and (newSetName not in setNames or not dirExists(newSetDir)): - initTree(newSetDir) + (newSetNameRep, newSetRo, newSetSrc) = self.setInfo(newSetName) + + if (not newSetSrc) and (newSetName not in setNames or not dirExists(newSetDir)): + initTree(newSetDir, fresh=False) setNames.add(newSetName) if newSetName != setName: setName = newSetName self.setName = setName - self.setNameRep = setName if setName else entitySet + self.setInfo() self.loadSetData() if not browse: @@ -169,6 +201,29 @@

                Module tf.browser.ner.sets

                f"Annotation set {setNameRep} has {nEntities} annotation{plural}" ) + def _addToSet(self, newEntities, silent=False): + """Add a bunch of entities to the current set. + + Only for sets that correspond to sheets. This is to create such a set, + it is not meant to call this function manually in a Jupyter notebook. + + Parameters + ---------- + newSetName: string + The name of the new annotation set to switch to. + """ + if not self.properlySetup: + return + + setIsRo = self.setIsRo + setIsSrc = self.setIsSrc + + if setIsSrc or not setIsRo: + return + + self._clearSetData() + self.addEntities(newEntities, silent=False, _lowlevel=True) + def resetSet(self): """Clear the current annotation set. @@ -179,9 +234,10 @@

                Module tf.browser.ner.sets

                settings = self.settings setName = self.setName + setIsRo = self.setIsRo entitySet = settings.entitySet - if not setName: + if setIsRo: self.console(f"Resetting the {entitySet} has no effect") return @@ -206,8 +262,8 @@

                Module tf.browser.ner.sets

                def setDup(self, dupSet): """Duplicates the current set to a set with a new name. - !!! hint "The special set can be duplicated" - After duplication of the special read-only set, the duplicate + !!! hint "The readonly sets can be duplicated" + After duplication of a read-only set, the duplicate copy is modifiable. In this way you can make corrections to the set of pre-existing, tool-generated annotations. @@ -225,6 +281,7 @@

                Module tf.browser.ner.sets

                setNames = self.setNames setsData = self.sets setName = self.setName + setIsSrc = self.setIsSrc annoDir = self.annoDir annoPath = f"{annoDir}/{dupSet}" @@ -233,7 +290,19 @@

                Module tf.browser.ner.sets

                if dupSet in setNames: messages.append((ERROR, f"""Set {dupSet} already exists""")) else: - if setName: + if setIsSrc: + dataFile = f"{annoPath}/entities.tsv" + + if fileExists(dataFile): + messages.append((ERROR, f"""Set {dupSet} already exists""")) + else: + dirMake(annoPath) + self.saveEntitiesAs(dataFile) + setNames.add(dupSet) + setsData[dupSet] = setsData[setName] + self.setName = dupSet + self.setInfo() + else: if not dirCopy( f"{annoDir}/{setName}", annoPath, @@ -246,17 +315,7 @@

                Module tf.browser.ner.sets

                setNames.add(dupSet) setsData[dupSet] = setsData[setName] self.setName = dupSet - else: - dataFile = f"{annoPath}/entities.tsv" - - if fileExists(dataFile): - messages.append((ERROR, f"""Set {dupSet} already exists""")) - else: - dirMake(annoPath) - self.saveEntitiesAs(dataFile) - setNames.add(dupSet) - setsData[dupSet] = setsData[setName] - self.setName = dupSet + self.setInfo() return messages @@ -276,9 +335,12 @@

                Module tf.browser.ner.sets

                return [] messages = [] + (delSetRep, delSetRo, delSetSrc) = self.setInfo(setName=delSet) - if delSet == "": - messages.append("""Cannot remove set "" because it is read-only""") + if delSetRo: + messages.append( + (ERROR, f"""Cannot remove set {delSetRep} because it is read-only""") + ) return messages setNames = self.setNames @@ -289,12 +351,13 @@

                Module tf.browser.ner.sets

                dirRemove(annoPath) if dirExists(annoPath): - messages.append((ERROR, f"""Could not remove {delSet}""")) + messages.append((ERROR, f"""Could not remove {delSetRep}""")) else: setNames.discard(delSet) del setsData[delSet] if self.setName == delSet: self.setName = "" + self.setInfo() return messages @@ -314,15 +377,18 @@

                Module tf.browser.ner.sets

                return [] messages = [] + (moveSetRep, moveSetRo, moveSetSrc) = self.setInfo(setName=moveSet) - if moveSet == "": - messages.append("""Cannot rename a set to "".""") + if moveSetRo: + messages.append((ERROR, f"""Cannot rename a set to ""{moveSetRep}""")) return messages setName = self.setName + setNameRep = self.setNameRep + setIsRo = self.setIsRo - if setName == "": - messages.append("""Cannot rename set "".""") + if setIsRo: + messages.append((ERROR, f"""Cannot rename set ""{setNameRep}""")) return messages setNames = self.setNames @@ -331,13 +397,13 @@

                Module tf.browser.ner.sets

                annoPath = f"{annoDir}/{moveSet}" if dirExists(annoPath): - messages.append((ERROR, f"""Set {moveSet} already exists""")) + messages.append((ERROR, f"""Set {moveSetRep} already exists""")) else: if not dirMove(f"{annoDir}/{setName}", annoPath): messages.append( ( ERROR, - f"""Could not rename {setName} to {moveSet}""", + f"""Could not rename {setNameRep} to {moveSetRep}""", ) ) else: @@ -346,6 +412,7 @@

                Module tf.browser.ner.sets

                setsData[moveSet] = setsData[setName] del setsData[setName] self.setName = moveSet + self.setInfo() return messages
                @@ -366,9 +433,15 @@

                Classes

                Methods to create, duplicate, rename and delete annotation sets.

                Annotation sets have names, given by the user.

                -

                There is one special annotation set, whose name is the empty string, +

                There is a special annotation set, whose name is the empty string, and whose content are the pre-existing entities, i.e. the entities that are present in the TF data as nodes and features.

                +

                Users can not name sets with names that start with a dot.

                +

                Annotation sets whose name start with a dot are generated by the system +when a family of spreadsheets with entity triggers is processed. +These sets are readonly, like the special annotation set, but they can +be duplicated to ordinary sets. Those copies loose the relationship with +the original spreadsheet.

                There is always one current annotation set, whose data is loaded into memory.

                Parameters

                @@ -380,7 +453,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                class Sets(Data):
                     def __init__(self, sets=None):
                @@ -388,10 +461,18 @@ 

                Parameters

                Annotation sets have names, given by the user. - There is one special annotation set, whose name is the empty string, + There is a special annotation set, whose name is the empty string, and whose content are the pre-existing entities, i.e. the entities that are present in the TF data as nodes and features. + Users can not name sets with names that start with a dot. + + Annotation sets whose name start with a dot are generated by the system + when a family of spreadsheets with entity triggers is processed. + These sets are readonly, like the special annotation set, but they can + be duplicated to ordinary sets. Those copies loose the relationship with + the original spreadsheet. + There is always one current annotation set, whose data is loaded into memory. @@ -401,19 +482,17 @@

                Parameters

                Entity sets to start with. If None, a fresh store of sets will be created by a parent class (Data). """ - super().__init__(sets=sets) + Data.__init__(self, sets=sets) + if not self.properlySetup: return browse = self.browse - settings = self.settings - entitySet = settings.entitySet self.setName = "" """The current annotation set.""" - self.setNameRep = entitySet - """The name representation of the current annotation set.""" + self.setInfo() self.setNames = set() """The set of names of annotation sets that are present on the file system.""" @@ -423,6 +502,33 @@

                Parameters

                if not browse: self.loadSetData() + def setInfo(self, setName=None): + settings = self.settings + entitySet = settings.entitySet + + inObject = False + + if setName is None: + setName = self.setName + inObject = True + + setIsRo = setName == "" or setName.startswith(".") + setIsSrc = setName == "" + + setNameRep = ( + f"🟰 {entitySet}" + if setName == "" + else f"🧾 {setName[1:]}" + if setName.startswith(".") + else f"🖍️ {setName}" + ) + if inObject: + self.setNameRep = setNameRep + self.setIsRo = setIsRo + self.setIsSrc = setIsSrc + else: + return (setNameRep, setIsRo, setIsSrc) + def readSets(self): """Read the list current annotation sets (again). @@ -433,8 +539,7 @@

                Parameters

                self.setNames = set(dirContents(annoDir)[1]) def getSetData(self): - """Deliver the current set. - """ + """Deliver the current set.""" setsData = self.sets setName = self.setName setData = setsData.setdefault(setName, AttrDict()) @@ -454,8 +559,6 @@

                Parameters

                if not self.properlySetup: return - settings = self.settings - entitySet = settings.entitySet browse = self.browse if not browse: @@ -467,14 +570,16 @@

                Parameters

                annoDir = self.annoDir newSetDir = f"{annoDir}/{newSetName}" - if newSetName and (newSetName not in setNames or not dirExists(newSetDir)): - initTree(newSetDir) + (newSetNameRep, newSetRo, newSetSrc) = self.setInfo(newSetName) + + if (not newSetSrc) and (newSetName not in setNames or not dirExists(newSetDir)): + initTree(newSetDir, fresh=False) setNames.add(newSetName) if newSetName != setName: setName = newSetName self.setName = setName - self.setNameRep = setName if setName else entitySet + self.setInfo() self.loadSetData() if not browse: @@ -486,6 +591,29 @@

                Parameters

                f"Annotation set {setNameRep} has {nEntities} annotation{plural}" ) + def _addToSet(self, newEntities, silent=False): + """Add a bunch of entities to the current set. + + Only for sets that correspond to sheets. This is to create such a set, + it is not meant to call this function manually in a Jupyter notebook. + + Parameters + ---------- + newSetName: string + The name of the new annotation set to switch to. + """ + if not self.properlySetup: + return + + setIsRo = self.setIsRo + setIsSrc = self.setIsSrc + + if setIsSrc or not setIsRo: + return + + self._clearSetData() + self.addEntities(newEntities, silent=False, _lowlevel=True) + def resetSet(self): """Clear the current annotation set. @@ -496,9 +624,10 @@

                Parameters

                settings = self.settings setName = self.setName + setIsRo = self.setIsRo entitySet = settings.entitySet - if not setName: + if setIsRo: self.console(f"Resetting the {entitySet} has no effect") return @@ -523,8 +652,8 @@

                Parameters

                def setDup(self, dupSet): """Duplicates the current set to a set with a new name. - !!! hint "The special set can be duplicated" - After duplication of the special read-only set, the duplicate + !!! hint "The readonly sets can be duplicated" + After duplication of a read-only set, the duplicate copy is modifiable. In this way you can make corrections to the set of pre-existing, tool-generated annotations. @@ -542,6 +671,7 @@

                Parameters

                setNames = self.setNames setsData = self.sets setName = self.setName + setIsSrc = self.setIsSrc annoDir = self.annoDir annoPath = f"{annoDir}/{dupSet}" @@ -550,7 +680,19 @@

                Parameters

                if dupSet in setNames: messages.append((ERROR, f"""Set {dupSet} already exists""")) else: - if setName: + if setIsSrc: + dataFile = f"{annoPath}/entities.tsv" + + if fileExists(dataFile): + messages.append((ERROR, f"""Set {dupSet} already exists""")) + else: + dirMake(annoPath) + self.saveEntitiesAs(dataFile) + setNames.add(dupSet) + setsData[dupSet] = setsData[setName] + self.setName = dupSet + self.setInfo() + else: if not dirCopy( f"{annoDir}/{setName}", annoPath, @@ -563,17 +705,7 @@

                Parameters

                setNames.add(dupSet) setsData[dupSet] = setsData[setName] self.setName = dupSet - else: - dataFile = f"{annoPath}/entities.tsv" - - if fileExists(dataFile): - messages.append((ERROR, f"""Set {dupSet} already exists""")) - else: - dirMake(annoPath) - self.saveEntitiesAs(dataFile) - setNames.add(dupSet) - setsData[dupSet] = setsData[setName] - self.setName = dupSet + self.setInfo() return messages @@ -593,9 +725,12 @@

                Parameters

                return [] messages = [] + (delSetRep, delSetRo, delSetSrc) = self.setInfo(setName=delSet) - if delSet == "": - messages.append("""Cannot remove set "" because it is read-only""") + if delSetRo: + messages.append( + (ERROR, f"""Cannot remove set {delSetRep} because it is read-only""") + ) return messages setNames = self.setNames @@ -606,12 +741,13 @@

                Parameters

                dirRemove(annoPath) if dirExists(annoPath): - messages.append((ERROR, f"""Could not remove {delSet}""")) + messages.append((ERROR, f"""Could not remove {delSetRep}""")) else: setNames.discard(delSet) del setsData[delSet] if self.setName == delSet: self.setName = "" + self.setInfo() return messages @@ -631,15 +767,18 @@

                Parameters

                return [] messages = [] + (moveSetRep, moveSetRo, moveSetSrc) = self.setInfo(setName=moveSet) - if moveSet == "": - messages.append("""Cannot rename a set to "".""") + if moveSetRo: + messages.append((ERROR, f"""Cannot rename a set to ""{moveSetRep}""")) return messages setName = self.setName + setNameRep = self.setNameRep + setIsRo = self.setIsRo - if setName == "": - messages.append("""Cannot rename set "".""") + if setIsRo: + messages.append((ERROR, f"""Cannot rename set ""{setNameRep}""")) return messages setNames = self.setNames @@ -648,13 +787,13 @@

                Parameters

                annoPath = f"{annoDir}/{moveSet}" if dirExists(annoPath): - messages.append((ERROR, f"""Set {moveSet} already exists""")) + messages.append((ERROR, f"""Set {moveSetRep} already exists""")) else: if not dirMove(f"{annoDir}/{setName}", annoPath): messages.append( ( ERROR, - f"""Could not rename {setName} to {moveSet}""", + f"""Could not rename {setNameRep} to {moveSetRep}""", ) ) else: @@ -663,6 +802,7 @@

                Parameters

                setsData[moveSet] = setsData[setName] del setsData[setName] self.setName = moveSet + self.setInfo() return messages
                @@ -682,10 +822,6 @@

                Instance variables

                The current annotation set.

                -
                var setNameRep
                -
                -

                The name representation of the current annotation set.

                -
                var setNames

                The set of names of annotation sets that are present on the file system.

                @@ -701,11 +837,10 @@

                Methods

                Expand source code -Browse git +Browse git
                def getSetData(self):
                -    """Deliver the current set.
                -    """
                +    """Deliver the current set."""
                     setsData = self.sets
                     setName = self.setName
                     setData = setsData.setdefault(setName, AttrDict())
                @@ -722,7 +857,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def readSets(self):
                     """Read the list current annotation sets (again).
                @@ -743,7 +878,7 @@ 

                Methods

                Expand source code -Browse git +Browse git
                def resetSet(self):
                     """Clear the current annotation set.
                @@ -755,9 +890,10 @@ 

                Methods

                settings = self.settings setName = self.setName + setIsRo = self.setIsRo entitySet = settings.entitySet - if not setName: + if setIsRo: self.console(f"Resetting the {entitySet} has no effect") return @@ -796,7 +932,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                def setDel(self, delSet):
                     """Remove a named set.
                @@ -814,9 +950,12 @@ 

                Parameters

                return [] messages = [] + (delSetRep, delSetRo, delSetSrc) = self.setInfo(setName=delSet) - if delSet == "": - messages.append("""Cannot remove set "" because it is read-only""") + if delSetRo: + messages.append( + (ERROR, f"""Cannot remove set {delSetRep} because it is read-only""") + ) return messages setNames = self.setNames @@ -827,12 +966,13 @@

                Parameters

                dirRemove(annoPath) if dirExists(annoPath): - messages.append((ERROR, f"""Could not remove {delSet}""")) + messages.append((ERROR, f"""Could not remove {delSetRep}""")) else: setNames.discard(delSet) del setsData[delSet] if self.setName == delSet: self.setName = "" + self.setInfo() return messages
                @@ -843,8 +983,8 @@

                Parameters

                Duplicates the current set to a set with a new name.

                -

                The special set can be duplicated

                -

                After duplication of the special read-only set, the duplicate +

                The readonly sets can be duplicated

                +

                After duplication of a read-only set, the duplicate copy is modifiable. In this way you can make corrections to the set of pre-existing, tool-generated annotations.

                @@ -858,13 +998,13 @@

                Parameters

                Expand source code -Browse git +Browse git
                def setDup(self, dupSet):
                     """Duplicates the current set to a set with a new name.
                 
                -    !!! hint "The special set can be duplicated"
                -        After duplication of the special read-only set, the duplicate
                +    !!! hint "The readonly sets can be duplicated"
                +        After duplication of a read-only set, the duplicate
                         copy is modifiable.
                         In this way you can make corrections to the set of pre-existing,
                         tool-generated annotations.
                @@ -882,6 +1022,7 @@ 

                Parameters

                setNames = self.setNames setsData = self.sets setName = self.setName + setIsSrc = self.setIsSrc annoDir = self.annoDir annoPath = f"{annoDir}/{dupSet}" @@ -890,7 +1031,19 @@

                Parameters

                if dupSet in setNames: messages.append((ERROR, f"""Set {dupSet} already exists""")) else: - if setName: + if setIsSrc: + dataFile = f"{annoPath}/entities.tsv" + + if fileExists(dataFile): + messages.append((ERROR, f"""Set {dupSet} already exists""")) + else: + dirMake(annoPath) + self.saveEntitiesAs(dataFile) + setNames.add(dupSet) + setsData[dupSet] = setsData[setName] + self.setName = dupSet + self.setInfo() + else: if not dirCopy( f"{annoDir}/{setName}", annoPath, @@ -903,21 +1056,49 @@

                Parameters

                setNames.add(dupSet) setsData[dupSet] = setsData[setName] self.setName = dupSet - else: - dataFile = f"{annoPath}/entities.tsv" - - if fileExists(dataFile): - messages.append((ERROR, f"""Set {dupSet} already exists""")) - else: - dirMake(annoPath) - self.saveEntitiesAs(dataFile) - setNames.add(dupSet) - setsData[dupSet] = setsData[setName] - self.setName = dupSet + self.setInfo() return messages
                +
                +def setInfo(self, setName=None) +
                +
                +
                +
                + +Expand source code +Browse git + +
                def setInfo(self, setName=None):
                +    settings = self.settings
                +    entitySet = settings.entitySet
                +
                +    inObject = False
                +
                +    if setName is None:
                +        setName = self.setName
                +        inObject = True
                +
                +    setIsRo = setName == "" or setName.startswith(".")
                +    setIsSrc = setName == ""
                +
                +    setNameRep = (
                +        f"🟰 {entitySet}"
                +        if setName == ""
                +        else f"🧾 {setName[1:]}"
                +        if setName.startswith(".")
                +        else f"🖍️ {setName}"
                +    )
                +    if inObject:
                +        self.setNameRep = setNameRep
                +        self.setIsRo = setIsRo
                +        self.setIsSrc = setIsSrc
                +    else:
                +        return (setNameRep, setIsRo, setIsSrc)
                +
                +
                def setMove(self, moveSet)
                @@ -934,7 +1115,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                def setMove(self, moveSet):
                     """Renames a named set.
                @@ -952,15 +1133,18 @@ 

                Parameters

                return [] messages = [] + (moveSetRep, moveSetRo, moveSetSrc) = self.setInfo(setName=moveSet) - if moveSet == "": - messages.append("""Cannot rename a set to "".""") + if moveSetRo: + messages.append((ERROR, f"""Cannot rename a set to ""{moveSetRep}""")) return messages setName = self.setName + setNameRep = self.setNameRep + setIsRo = self.setIsRo - if setName == "": - messages.append("""Cannot rename set "".""") + if setIsRo: + messages.append((ERROR, f"""Cannot rename set ""{setNameRep}""")) return messages setNames = self.setNames @@ -969,13 +1153,13 @@

                Parameters

                annoPath = f"{annoDir}/{moveSet}" if dirExists(annoPath): - messages.append((ERROR, f"""Set {moveSet} already exists""")) + messages.append((ERROR, f"""Set {moveSetRep} already exists""")) else: if not dirMove(f"{annoDir}/{setName}", annoPath): messages.append( ( ERROR, - f"""Could not rename {setName} to {moveSet}""", + f"""Could not rename {setNameRep} to {moveSetRep}""", ) ) else: @@ -984,6 +1168,7 @@

                Parameters

                setsData[moveSet] = setsData[setName] del setsData[setName] self.setName = moveSet + self.setInfo() return messages
                @@ -1003,7 +1188,7 @@

                Parameters

                Expand source code -Browse git +Browse git
                def setSet(self, newSetName):
                     """Switch to a named annotation set.
                @@ -1019,8 +1204,6 @@ 

                Parameters

                if not self.properlySetup: return - settings = self.settings - entitySet = settings.entitySet browse = self.browse if not browse: @@ -1032,14 +1215,16 @@

                Parameters

                annoDir = self.annoDir newSetDir = f"{annoDir}/{newSetName}" - if newSetName and (newSetName not in setNames or not dirExists(newSetDir)): - initTree(newSetDir) + (newSetNameRep, newSetRo, newSetSrc) = self.setInfo(newSetName) + + if (not newSetSrc) and (newSetName not in setNames or not dirExists(newSetDir)): + initTree(newSetDir, fresh=False) setNames.add(newSetName) if newSetName != setName: setName = newSetName self.setName = setName - self.setNameRep = setName if setName else entitySet + self.setInfo() self.loadSetData() if not browse: @@ -1169,9 +1354,9 @@

                S
              • resetSet
              • setDel
              • setDup
              • +
              • setInfo
              • setMove
              • setName
              • -
              • setNameRep
              • setNames
              • setSet
              diff --git a/tf/browser/ner/settings.html b/tf/browser/ner/settings.html index 79ef706f6..3034b29e4 100644 --- a/tf/browser/ner/settings.html +++ b/tf/browser/ner/settings.html @@ -34,7 +34,7 @@

              Module tf.browser.ner.settings

              Expand source code -Browse git +Browse git
              """Corpus dependent setup of the annotation tool.
               
              @@ -393,7 +393,7 @@ 

              Classes

              Expand source code -Browse git +Browse git
              class Settings:
                   def __init__(self):
              @@ -455,7 +455,7 @@ 

              Methods

              Expand source code -Browse git +Browse git
              def console(self, msg, **kwargs):
                   """Print something to the output.
              diff --git a/tf/browser/ner/sheets.html b/tf/browser/ner/sheets.html
              index a1f1e0e0f..a15bba987 100644
              --- a/tf/browser/ner/sheets.html
              +++ b/tf/browser/ner/sheets.html
              @@ -31,17 +31,17 @@ 

              Module tf.browser.ner.sheets

              Expand source code -Browse git +Browse git
              import collections
               import re
               import time
               
               from ...capable import CheckImport
              -from .helpers import tnorm, normalize, toId, toSmallId, toTokens, log
              +from .helpers import tnorm, normalize, toSmallId, toTokens, consoleLine, repSet
               from ...core.generic import AttrDict
               from ...core.helpers import console
              -from ...core.files import dirContents, extNm, fileExists, mTime, initTree
              +from ...core.files import dirContents, extNm, fileExists, mTime
               
               
               DS_STORE = ".DS_Store"
              @@ -86,12 +86,13 @@ 

              Module tf.browser.ner.sheets

              The values are names plus the sheet where they are first defined. """ + self.logData = [] + if not browse: self.loadSheetData() def getSheetData(self): - """Deliver the current sheet. - """ + """Deliver the current sheet.""" sheetName = self.sheetName if sheetName is None: @@ -118,10 +119,6 @@

              Module tf.browser.ner.sheets

              sheetName = self.sheetName - if not newSheet: - self.sheetName = None - return - sheetNames = self.sheetNames sheetDir = self.sheetDir sheetFile = f"{sheetDir}/{newSheet}.xlsx" @@ -131,14 +128,16 @@

              Module tf.browser.ner.sheets

              self.console(f"Ner sheet {newSheet} ({sheetFile}) does not exist") return + self.setSet("" if newSheet is None else f".{newSheet}") + if newSheet != sheetName: sheetName = newSheet self.sheetName = sheetName - self.loadSheetData() + + self.loadSheetData() def loadSheetData(self): - """Loads the current ner sheet into memory, if there is one. - """ + """Loads the current ner sheet into memory, if there is one.""" if not self.properlySetup: return @@ -171,6 +170,7 @@

              Module tf.browser.ner.sheets

              if not self.properlySetup: return None + logData = self.logData sheetName = self.sheetName if sheetName is None: @@ -183,10 +183,6 @@

              Module tf.browser.ner.sheets

              sheetDir = self.sheetDir sheetFile = f"{sheetDir}/{sheetName}.xlsx" - reportBase = self.reportBase - reportDir = f"{reportBase}/{sheetName}" - initTree(reportDir, fresh=False) - def timeXls(sheetRela): sep = "/" if sheetRela else "" sheetPath = f"{sheetDir}/{sheetName}{sep}{sheetRela}.xlsx" @@ -213,14 +209,77 @@

              Module tf.browser.ner.sheets

              or (fileExists(sheetFile) and sheetData.dateLoaded < mT) ): changed = True + self.clearLog() self._readSheets(sheetData) self._combineSheets(sheetData) self._compileSheets(sheetData) self._prepareSheets(sheetData) sheetData.dateLoaded = time.time() + self.writeLog() + else: + if len(logData) == 0: + self.showLog() + else: + self.readLog() return changed + def showLog(self): + browse = self.browse + logData = self.logData + + if not browse: + for x in logData: + consoleLine(*x) + + def clearLog(self): + self.logData.clear() + + def readLog(self): + browse = self.browse + logData = self.logData + setName = self.setName + annoDir = self.annoDir + setDir = f"{annoDir}/{setName}" + logFile = f"{setDir}/excel.tsv" + + if fileExists(logFile): + self.clearLog() + + with open(logFile) as fh: + for line in fh: + fields = line.rstrip("\n").split("\t") + isError = None if fields[0] == "special" else fields[0] == "error" + indent = int(fields[1]) + msg = fields[2] + logData.append((isError, indent, msg)) + + if not browse: + consoleLine(isError, indent, msg) + + def writeLog(self): + logData = self.logData + setName = self.setName + annoDir = self.annoDir + setDir = f"{annoDir}/{setName}" + logFile = f"{setDir}/excel.tsv" + + with open(logFile, "w") as fh: + for fields in logData: + mode = ( + "special" if fields[0] is None else "error" if fields[0] else "info" + ) + fh.write(f"{mode}\t{fields[1]}\t{fields[2]}\n") + + def log(self, isError, indent, msg): + browse = self.browse + logData = self.logData + + logData.append((isError, indent, msg)) + + if not browse: + consoleLine(isError, indent, msg) + def processSheet(self, changed): """Generates derived data structures out of the source sheet. @@ -264,20 +323,20 @@

              Module tf.browser.ner.sheets

              or dateLoaded is not None and dateProcessed < dateLoaded ): - if not browse: app = self.app app.indent(reset=True) app.info("Looking up occurrences of many candidates ...") self.findOccs() - self.markEntities() - sheetData.dateProcessed = time.time() if not browse: app.info("done") self.reportHits() + self._markEntities() + sheetData.dateProcessed = time.time() + def readSheets(self): """Read the list current ner sheets (again). @@ -305,11 +364,25 @@

              Module tf.browser.ner.sheets

              nameMap = self.nameMap spaceEscaped = self.spaceEscaped - reportBase = self.reportBase - reportDir = f"{reportBase}/{sheetName}" - reportFile = f"{reportDir}/read.txt" - rh = open(reportFile, "w") - log(rh, "Reading the spreadsheets") + def spec(msg): + self.log(None, 0, msg) + + def log(msg): + self.log(False, 0, msg) + + def log1(msg): + self.log(False, 1, msg) + + def log2(msg): + self.log(False, 2, msg) + + def err(msg): + self.log(True, 0, msg) + + def err1(msg): + self.log(True, 1, msg) + + spec("Reading sheets") def readXls(sheetRela): sep = "/" if sheetRela else "" @@ -326,6 +399,7 @@

              Module tf.browser.ner.sheets

              sheet = {} idFirstRow = {} + noTrig = 0 for r, row in enumerate(ws.rows): if r in {0, 1}: @@ -346,37 +420,46 @@

              Module tf.browser.ner.sheets

              } ) if not name: - name = list(triggers)[0] if triggers else "" + name = list(triggers)[0] if len(triggers) else "" + if name == "": if kind: - log( - rh, + msg = ( f"{sheetRep} row {r + 1:>3}: {kind}: " - "no entity name and no triggers", + "no entity name and no triggers" ) + log(msg) continue else: - log( - rh, + msg = ( f"{sheetRep} row {r + 1:>3}: {kind}: " - f"no entity name, supplied synonym {name}", + f"no entity name, supplied synonym {name}" ) + log(msg) if not kind: kind = defaultKind - log( - rh, + msg = ( f"{sheetRep} row {r + 1:>3}: " - f"no kind name, supplied {defaultKind}", + f"no kind name, supplied {defaultKind}" ) + log(msg) eid = toSmallId(name, transform=transform) eidkind = (eid, kind) + ekRep = f"{kind}-{eid}" firstRowEid = idFirstRow.get((eidkind), None) if firstRowEid is None: idFirstRow[eidkind] = (r, name) - sheet[eidkind] = triggers + + if len(triggers) == 0: + if sheetRela == "": + noTrig += 1 + else: + sheet[eidkind] = triggers + else: + sheet[eidkind] = triggers prev = nameMap.get(eidkind, None) @@ -386,44 +469,30 @@

              Module tf.browser.ner.sheets

              (prevName, prevSheet) = prev if prevName != name: - if toId(prevName) == toId(name): - severity = "minor" - error = False - else: - severity = "major" - error = True - - log( - rh, - f"{sheetRep} {severity} name variant for {eidkind}:\n" - f" in {prevSheet:<30} : '{prevName}'\n" - f" in {sheetRep:<30} : '{name}'", - error=error, - ) - log(rh, f" will use '{prevName}' for {eidkind}") + err(f"{ekRep} in {sheetRep}:") + log1(f"{prevName}: ✅ in {prevSheet}") + log1(f"{name}: ❌ in {sheetRep}") else: (firstRow, firstName) = firstRowEid + err(f"{ekRep} in {sheetRep}:") + if firstName == name: - severity = "identical" - error = False - elif toId(firstName) == toId(name): - severity = "minor variant in" - error = False + log1(f"{name}: in {firstRow + 1:<3} and {r + 1}") + log2(repSet(triggers)) + log2(repSet(sheet.get(eidkind, set()))) else: - severity = "major variant in" - error = True - - log( - rh, - f"{sheetRep} {severity} name for {eidkind}:\n" - f" in {firstRow + 1:<3} : '{firstName}'\n" - f" in {r + 1:<3} : '{name}'\n", - error=error, - ) - log(rh, f" will merge triggers {triggers} with {sheet[eidkind]}") - sheet[eidkind] |= triggers + log1(f"{firstName}: in {firstRow + 1:<3}") + log2(repSet(triggers)) + log1(f"{name}: in {r + 1:<3}") + log2(repSet(sheet.get(eidkind, set()))) + + theseTriggers = sheet.get(eidkind, set()) | triggers + if len(theseTriggers): + sheet[eidkind] = theseTriggers + if noTrig > 0: + err(f"{sheetRep} has {noTrig} names without triggers") return sheet def readDir(sheetRela, level): @@ -441,7 +510,7 @@

              Module tf.browser.ner.sheets

              match = SHEET_RE.match(file) if not match: - log(rh, f"{sheetRep} contains unrecognized file {file}") + log(f"{sheetRep} contains unrecognized file {file}") continue (start, end) = match.group(1, 2) @@ -458,21 +527,20 @@

              Module tf.browser.ner.sheets

              for dr in dirs: if level >= 3: - log(rh, f"{sheetRep} is at max depth, yet contains subdir {dr}") + log(f"{sheetRep} is at max depth, yet contains subdir {dr}") continue if not dr.isdecimal(): - log(rh, f"{sheetRep} contains non-numeric subdir {dr}") + log(f"{sheetRep} contains non-numeric subdir {dr}") continue sheetSubdirs[int(dr)] = readDir(f"{sheetRela}{sep}{dr}", level + 1) - return dict(sng=sheetSingle, rng=sheetRange, sdr=sheetSubdirs) + return AttrDict(sng=sheetSingle, rng=sheetRange, sdr=sheetSubdirs) sheetMain = readXls("") sheetSubdirs = readDir("", 1) - sheetData.raw = dict(main=sheetMain, sdr=sheetSubdirs) - rh.close() + sheetData.raw = AttrDict(main=sheetMain, sdr=sheetSubdirs) def _combineSheets(self, sheetData): """Combines the spreadsheet info in single-section spreadsheets. @@ -484,37 +552,35 @@

              Module tf.browser.ner.sheets

              """ raw = sheetData.raw - sheetMain = raw["main"] - sheetTweaked = raw["sdr"] + sheetMain = raw.main + sheetTweaked = raw.sdr # combine the info in ranged sheets into single number sheets - combined = dict(sheet=sheetMain, tweaks={}) + combined = AttrDict(sheet=sheetMain, tweaks=AttrDict()) sheetData.combined = combined - console("Combining the spreadsheets") - def combineDir(info, dest): - ranged = info.get("rng", {}) - single = info.get("sng", {}) - subdirs = info.get("sdr", {}) + ranged = info.rng or {} + single = info.sng or {} + subdirs = info.sdr or {} for (start, end), sheet in sorted(ranged.items()): for i in range(start, end + 1): - updateDest = dest.setdefault(i, {}).setdefault("sheet", {}) + updateDest = dest.setdefault(i, AttrDict()).setdefault("sheet", {}) for eidkind, triggers in sheet.items(): updateDest[eidkind] = triggers for i, sheet in single.items(): - updateDest = dest.setdefault(i, {}).setdefault("sheet", {}) + updateDest = dest.setdefault(i, AttrDict()).setdefault("sheet", {}) for eidkind, triggers in sheet.items(): updateDest[eidkind] = triggers for i, tweaks in subdirs.items(): - updateDest = dest.setdefault(i, {}).setdefault("tweaks", {}) + updateDest = dest.setdefault(i, AttrDict()).setdefault("tweaks", {}) combineDir(tweaks, updateDest) - combineDir(sheetTweaked, combined["tweaks"]) + combineDir(sheetTweaked, combined.tweaks) def _compileSheets(self, sheetData): """Compiles the info in tweaked sheets into complete sheets. @@ -531,31 +597,44 @@

              Module tf.browser.ner.sheets

              The tweak may remove triggers from the sheet. We have to adapt the tMap for that. """ - + nameMap = self.nameMap combined = sheetData.combined - compiled = {} + compiled = AttrDict() sheetData.compiled = compiled - console("Compiling the spreadsheets") + def spec(msg): + self.log(None, 0, msg) + + def err(msg): + self.log(True, 0, msg) + + spec("Compiling data") def compileSheet(path, parentData, info, dest): - parentSheet = parentData["sheet"] - sheet = info["sheet"] + parentSheet = parentData.sheet + sheet = info.sheet newSheet = {} - dest["sheet"] = newSheet - parentTMap = parentData.get("tMap", {}) + dest.sheet = newSheet + parentTMap = parentData.tMap or {} newTMap = {} - dest["tMap"] = newTMap + dest.tMap = newTMap + pathRep = f"[{'.'.join(str(i) for i in path)}]" for eidkind, triggers in parentSheet.items(): newSheet[eidkind] = triggers for eidkind, triggers in sheet.items(): - newSheet[eidkind] = triggers + if len(triggers) == 0: + if eidkind in newSheet: + del newSheet[eidkind] + else: + err(f"{pathRep} {nameMap[eidkind][0]} has no triggers") + else: + newSheet[eidkind] = triggers - for trigger in triggers: - newTMap[trigger] = tuple(str(k) for k in path) + for trigger in triggers: + newTMap[trigger] = tuple(str(k) for k in path) for eidkind, triggers in newSheet.items(): for trigger in triggers: @@ -565,14 +644,17 @@

              Module tf.browser.ner.sheets

              def compileDir(path, parentData, info, dest): if "sheet" in info: compileSheet(path, parentData, info, dest) - parentData = dict(sheet=dest["sheet"], tMap=dest["tMap"]) + parentData = AttrDict(sheet=dest.sheet, tMap=dest.tMap) - tweaks = info.get("tweaks", {}) + tweaks = info.tweaks or {} tweakDest = dest.setdefault("tweaks", {}) for k in sorted(tweaks): compileDir( - path + (k,), parentData, tweaks[k], tweakDest.setdefault(k, {}) + path + (k,), + parentData, + tweaks[k], + tweakDest.setdefault(k, AttrDict()), ) compileDir((), combined, combined, compiled) @@ -619,27 +701,38 @@

              Module tf.browser.ner.sheets

              nameMap = self.nameMap compiled = sheetData.compiled - sheetName = self.sheetName - instructions = {} sheetData.instructions = instructions - reportBase = self.reportBase - reportDir = f"{reportBase}/{sheetName}" - reportFile = f"{reportDir}/check.tsv" + def spec(msg): + self.log(None, 0, msg) + + def log(msg): + self.log(False, 0, msg) + + def log1(msg): + self.log(False, 1, msg) + + def log2(msg): + self.log(False, 2, msg) + + def log3(msg): + self.log(False, 3, msg) + + def err(msg): + self.log(True, 0, msg) - console("Checking the spreadsheets") + def err1(msg): + self.log(True, 1, msg) - checkData = ["sheet\tentities\tnotriggers\ttriggers\tambiguous\n"] - ambiData = [] - notrigData = [] + def err2(msg): + self.log(True, 2, msg) - mainNotrigData = set() + spec("Checking triggers ...") def prepareSheet(path, info): - isMain = len(path) == 0 - sheet = info["sheet"] - tMap = info["tMap"] + sheet = info.sheet + tMap = info.tMap sheetR = ".".join(path) sheetRep = f"[{sheetR}]" @@ -647,20 +740,11 @@

              Module tf.browser.ner.sheets

              tPos = collections.defaultdict(lambda: collections.defaultdict(set)) idMap = collections.defaultdict(list) - prepared = dict(tPos=tPos, tMap=tMap) + prepared = AttrDict(tPos=tPos, tMap=tMap) instructions[path] = prepared for eidkind, triggers in sheet.items(): - if len(triggers) == 0: - name = nameMap[eidkind][0] - - if isMain: - mainNotrigData.add(name) - else: - if name not in mainNotrigData: - notrigData.append((name, sheetR)) - for trigger in triggers: triggerT = toTokens(trigger, spaceEscaped=spaceEscaped) triggerSet.add(triggerT) @@ -670,17 +754,15 @@

              Module tf.browser.ner.sheets

              for i, token in enumerate(triggerT): tPos[i][token].add(triggerT) - prepared["idMap"] = { + prepared.idMap = { trigger: eidkinds[0] for (trigger, eidkinds) in idMap.items() } nEnt = len(sheet) nTriggers = sum(len(triggers) for triggers in sheet.values()) noTriggers = sum(1 for triggers in sheet.values() if len(triggers) == 0) - noTrigMsg = "" if noTriggers == 0 else f", {noTriggers} without triggers;" - ambi = 0 - msgs = [] + ambis = collections.defaultdict(list) for trigger, eidkinds in sorted(idMap.items()): if len(eidkinds) <= 1: @@ -691,60 +773,61 @@

              Module tf.browser.ner.sheets

              if path != tPath: continue - msgs.append(f""" trigger '{trigger}' used for:""") - for eidkind in eidkinds: name = nameMap[eidkind][0] - msgs.append(f"\t{name}") + ambis[trigger].append(name) - ambiData.append((trigger, sheetR, name)) + log(f"{sheetRep} {nTriggers} triggers for {nEnt} entities") - ambi += 1 + if noTriggers > 0: + err1(f"{noTriggers} without triggers") - ambiMsg = "" if ambi == 0 else f", {ambi} ambiguous" + nAmbi = len(ambis) - entMsg = f"entities: {nEnt} {noTrigMsg}" - triggerMsg = f"triggers: {nTriggers} {ambiMsg}" + if nAmbi > 0: + err1(f"{nAmbi} ambiguous triggers") - console(f"{sheetRep:<25}: {entMsg:<35} {triggerMsg}") + for trigger, names in ambis.items(): + err2(trigger) - if len(msgs): - console("\n".join(msgs)) - - checkData.append(f"{sheetR}\t{nEnt}\t{noTriggers}\t{nTriggers}\t{ambi}\n") + for name in names: + log3(name) def prepareDir(path, info): if "sheet" in info: prepareSheet(path, info) - tweaks = info.get("tweaks", {}) + tweaks = info.tweaks or {} for k in sorted(tweaks): prepareDir(path + (str(k),), tweaks[k]) prepareDir((), compiled) - with open(reportFile, "w") as rh: - for c in checkData: - rh.write(c) + def _markEntities(self): + """Marks up the members of the inventory as entities. - notrigFile = f"{reportDir}/notriggers.tsv" + The instructions contain the entity identifier and the entity kind that + have to be assigned to the surface forms. - with open(notrigFile, "w") as nh: - nh.write("name\tsheet\n") + The inventory knows where the occurrences of the surface forms are. + If there is no inventory yet, it will be created. + """ + if not self.properlySetup: + return - for name in sorted(mainNotrigData): - nh.write(f"{name}\t\n") - for name, sheet in sorted(notrigData): - nh.write(f"{name}\t{sheet}\n") + sheetName = self.sheetName + sheetData = self.sheets[sheetName] + inventory = sheetData.inventory - ambiFile = f"{reportDir}/ambitriggers.tsv" + newEntities = [] - with open(ambiFile, "w") as ah: - ah.write("trigger\tname\tsheet\n") + for eidkind, entData in inventory.items(): + for trigger, triggerData in entData.items(): + for matches in triggerData.values(): + newEntities.append((eidkind, matches)) - for trigger, sheet, name in sorted(ambiData): - ah.write(f"{trigger}\t{sheet}\t{name}\n") + self._addToSet(newEntities, silent=False) def showSheetsRaw(self, main=False): src = self.getSheetData() @@ -769,25 +852,25 @@

              Module tf.browser.ner.sheets

              tab = " " * level console(f"{tab}{head}") - rng = tweaks.get("rng", {}) + rng = tweaks.rng or {} for b, e in sorted(rng): console(f"{tab} {b}-{e}.xslx") showSheet(rng[(b, e)], tab) - sng = tweaks.get("sng", {}) + sng = tweaks.sng or {} for k in sorted(sng): console(f"{tab} {k}.xslx") showSheet(sng[k], tab) - sdr = tweaks.get("sdr", {}) + sdr = tweaks.sdr or {} for k in sorted(sdr): showDir(k, sdr[k], level + 1) if main: - showSheet(src["main"], "") + showSheet(src.main, "") - showDir("", src["sdr"], 0) + showDir("", src.sdr, 0) def showSheetsCombined(self, main=False): src = self.getSheetData() @@ -814,9 +897,9 @@

              Module tf.browser.ner.sheets

              if "sheet" in info: if main or level > 0: - showSheet(info["sheet"], tab) + showSheet(info.sheet, tab) - tweaks = info.get("tweaks", {}) + tweaks = info.tweaks or {} for k in sorted(tweaks): showDir(k, tweaks[k], level + 1) @@ -828,8 +911,8 @@

              Module tf.browser.ner.sheets

              src = self.compiled def showSheet(info, tab): - sheet = info["sheet"] - tMap = info["tMap"] + sheet = info.sheet + tMap = info.tMap for eidkind, triggers in sorted(sheet.items()): triggerSources = {tMap[t] for t in triggers} @@ -864,7 +947,7 @@

              Module tf.browser.ner.sheets

              if main or level > 0: showSheet(info, tab) - tweaks = info.get("tweaks", {}) + tweaks = info.tweaks or {} for k in sorted(tweaks): showDir(k, tweaks[k], level + 1) @@ -900,7 +983,7 @@

              Classes

              Expand source code -Browse git +Browse git
              class Sheets:
                   def __init__(self, sheets=None):
              @@ -940,12 +1023,13 @@ 

              Classes

              The values are names plus the sheet where they are first defined. """ + self.logData = [] + if not browse: self.loadSheetData() def getSheetData(self): - """Deliver the current sheet. - """ + """Deliver the current sheet.""" sheetName = self.sheetName if sheetName is None: @@ -972,10 +1056,6 @@

              Classes

              sheetName = self.sheetName - if not newSheet: - self.sheetName = None - return - sheetNames = self.sheetNames sheetDir = self.sheetDir sheetFile = f"{sheetDir}/{newSheet}.xlsx" @@ -985,14 +1065,16 @@

              Classes

              self.console(f"Ner sheet {newSheet} ({sheetFile}) does not exist") return + self.setSet("" if newSheet is None else f".{newSheet}") + if newSheet != sheetName: sheetName = newSheet self.sheetName = sheetName - self.loadSheetData() + + self.loadSheetData() def loadSheetData(self): - """Loads the current ner sheet into memory, if there is one. - """ + """Loads the current ner sheet into memory, if there is one.""" if not self.properlySetup: return @@ -1025,6 +1107,7 @@

              Classes

              if not self.properlySetup: return None + logData = self.logData sheetName = self.sheetName if sheetName is None: @@ -1037,10 +1120,6 @@

              Classes

              sheetDir = self.sheetDir sheetFile = f"{sheetDir}/{sheetName}.xlsx" - reportBase = self.reportBase - reportDir = f"{reportBase}/{sheetName}" - initTree(reportDir, fresh=False) - def timeXls(sheetRela): sep = "/" if sheetRela else "" sheetPath = f"{sheetDir}/{sheetName}{sep}{sheetRela}.xlsx" @@ -1067,14 +1146,77 @@

              Classes

              or (fileExists(sheetFile) and sheetData.dateLoaded < mT) ): changed = True + self.clearLog() self._readSheets(sheetData) self._combineSheets(sheetData) self._compileSheets(sheetData) self._prepareSheets(sheetData) sheetData.dateLoaded = time.time() + self.writeLog() + else: + if len(logData) == 0: + self.showLog() + else: + self.readLog() return changed + def showLog(self): + browse = self.browse + logData = self.logData + + if not browse: + for x in logData: + consoleLine(*x) + + def clearLog(self): + self.logData.clear() + + def readLog(self): + browse = self.browse + logData = self.logData + setName = self.setName + annoDir = self.annoDir + setDir = f"{annoDir}/{setName}" + logFile = f"{setDir}/excel.tsv" + + if fileExists(logFile): + self.clearLog() + + with open(logFile) as fh: + for line in fh: + fields = line.rstrip("\n").split("\t") + isError = None if fields[0] == "special" else fields[0] == "error" + indent = int(fields[1]) + msg = fields[2] + logData.append((isError, indent, msg)) + + if not browse: + consoleLine(isError, indent, msg) + + def writeLog(self): + logData = self.logData + setName = self.setName + annoDir = self.annoDir + setDir = f"{annoDir}/{setName}" + logFile = f"{setDir}/excel.tsv" + + with open(logFile, "w") as fh: + for fields in logData: + mode = ( + "special" if fields[0] is None else "error" if fields[0] else "info" + ) + fh.write(f"{mode}\t{fields[1]}\t{fields[2]}\n") + + def log(self, isError, indent, msg): + browse = self.browse + logData = self.logData + + logData.append((isError, indent, msg)) + + if not browse: + consoleLine(isError, indent, msg) + def processSheet(self, changed): """Generates derived data structures out of the source sheet. @@ -1118,20 +1260,20 @@

              Classes

              or dateLoaded is not None and dateProcessed < dateLoaded ): - if not browse: app = self.app app.indent(reset=True) app.info("Looking up occurrences of many candidates ...") self.findOccs() - self.markEntities() - sheetData.dateProcessed = time.time() if not browse: app.info("done") self.reportHits() + self._markEntities() + sheetData.dateProcessed = time.time() + def readSheets(self): """Read the list current ner sheets (again). @@ -1159,11 +1301,25 @@

              Classes

              nameMap = self.nameMap spaceEscaped = self.spaceEscaped - reportBase = self.reportBase - reportDir = f"{reportBase}/{sheetName}" - reportFile = f"{reportDir}/read.txt" - rh = open(reportFile, "w") - log(rh, "Reading the spreadsheets") + def spec(msg): + self.log(None, 0, msg) + + def log(msg): + self.log(False, 0, msg) + + def log1(msg): + self.log(False, 1, msg) + + def log2(msg): + self.log(False, 2, msg) + + def err(msg): + self.log(True, 0, msg) + + def err1(msg): + self.log(True, 1, msg) + + spec("Reading sheets") def readXls(sheetRela): sep = "/" if sheetRela else "" @@ -1180,6 +1336,7 @@

              Classes

              sheet = {} idFirstRow = {} + noTrig = 0 for r, row in enumerate(ws.rows): if r in {0, 1}: @@ -1200,37 +1357,46 @@

              Classes

              } ) if not name: - name = list(triggers)[0] if triggers else "" + name = list(triggers)[0] if len(triggers) else "" + if name == "": if kind: - log( - rh, + msg = ( f"{sheetRep} row {r + 1:>3}: {kind}: " - "no entity name and no triggers", + "no entity name and no triggers" ) + log(msg) continue else: - log( - rh, + msg = ( f"{sheetRep} row {r + 1:>3}: {kind}: " - f"no entity name, supplied synonym {name}", + f"no entity name, supplied synonym {name}" ) + log(msg) if not kind: kind = defaultKind - log( - rh, + msg = ( f"{sheetRep} row {r + 1:>3}: " - f"no kind name, supplied {defaultKind}", + f"no kind name, supplied {defaultKind}" ) + log(msg) eid = toSmallId(name, transform=transform) eidkind = (eid, kind) + ekRep = f"{kind}-{eid}" firstRowEid = idFirstRow.get((eidkind), None) if firstRowEid is None: idFirstRow[eidkind] = (r, name) - sheet[eidkind] = triggers + + if len(triggers) == 0: + if sheetRela == "": + noTrig += 1 + else: + sheet[eidkind] = triggers + else: + sheet[eidkind] = triggers prev = nameMap.get(eidkind, None) @@ -1240,44 +1406,30 @@

              Classes

              (prevName, prevSheet) = prev if prevName != name: - if toId(prevName) == toId(name): - severity = "minor" - error = False - else: - severity = "major" - error = True - - log( - rh, - f"{sheetRep} {severity} name variant for {eidkind}:\n" - f" in {prevSheet:<30} : '{prevName}'\n" - f" in {sheetRep:<30} : '{name}'", - error=error, - ) - log(rh, f" will use '{prevName}' for {eidkind}") + err(f"{ekRep} in {sheetRep}:") + log1(f"{prevName}: ✅ in {prevSheet}") + log1(f"{name}: ❌ in {sheetRep}") else: (firstRow, firstName) = firstRowEid + err(f"{ekRep} in {sheetRep}:") + if firstName == name: - severity = "identical" - error = False - elif toId(firstName) == toId(name): - severity = "minor variant in" - error = False + log1(f"{name}: in {firstRow + 1:<3} and {r + 1}") + log2(repSet(triggers)) + log2(repSet(sheet.get(eidkind, set()))) else: - severity = "major variant in" - error = True - - log( - rh, - f"{sheetRep} {severity} name for {eidkind}:\n" - f" in {firstRow + 1:<3} : '{firstName}'\n" - f" in {r + 1:<3} : '{name}'\n", - error=error, - ) - log(rh, f" will merge triggers {triggers} with {sheet[eidkind]}") - sheet[eidkind] |= triggers + log1(f"{firstName}: in {firstRow + 1:<3}") + log2(repSet(triggers)) + log1(f"{name}: in {r + 1:<3}") + log2(repSet(sheet.get(eidkind, set()))) + + theseTriggers = sheet.get(eidkind, set()) | triggers + if len(theseTriggers): + sheet[eidkind] = theseTriggers + if noTrig > 0: + err(f"{sheetRep} has {noTrig} names without triggers") return sheet def readDir(sheetRela, level): @@ -1295,7 +1447,7 @@

              Classes

              match = SHEET_RE.match(file) if not match: - log(rh, f"{sheetRep} contains unrecognized file {file}") + log(f"{sheetRep} contains unrecognized file {file}") continue (start, end) = match.group(1, 2) @@ -1312,21 +1464,20 @@

              Classes

              for dr in dirs: if level >= 3: - log(rh, f"{sheetRep} is at max depth, yet contains subdir {dr}") + log(f"{sheetRep} is at max depth, yet contains subdir {dr}") continue if not dr.isdecimal(): - log(rh, f"{sheetRep} contains non-numeric subdir {dr}") + log(f"{sheetRep} contains non-numeric subdir {dr}") continue sheetSubdirs[int(dr)] = readDir(f"{sheetRela}{sep}{dr}", level + 1) - return dict(sng=sheetSingle, rng=sheetRange, sdr=sheetSubdirs) + return AttrDict(sng=sheetSingle, rng=sheetRange, sdr=sheetSubdirs) sheetMain = readXls("") sheetSubdirs = readDir("", 1) - sheetData.raw = dict(main=sheetMain, sdr=sheetSubdirs) - rh.close() + sheetData.raw = AttrDict(main=sheetMain, sdr=sheetSubdirs) def _combineSheets(self, sheetData): """Combines the spreadsheet info in single-section spreadsheets. @@ -1338,37 +1489,35 @@

              Classes

              """ raw = sheetData.raw - sheetMain = raw["main"] - sheetTweaked = raw["sdr"] + sheetMain = raw.main + sheetTweaked = raw.sdr # combine the info in ranged sheets into single number sheets - combined = dict(sheet=sheetMain, tweaks={}) + combined = AttrDict(sheet=sheetMain, tweaks=AttrDict()) sheetData.combined = combined - console("Combining the spreadsheets") - def combineDir(info, dest): - ranged = info.get("rng", {}) - single = info.get("sng", {}) - subdirs = info.get("sdr", {}) + ranged = info.rng or {} + single = info.sng or {} + subdirs = info.sdr or {} for (start, end), sheet in sorted(ranged.items()): for i in range(start, end + 1): - updateDest = dest.setdefault(i, {}).setdefault("sheet", {}) + updateDest = dest.setdefault(i, AttrDict()).setdefault("sheet", {}) for eidkind, triggers in sheet.items(): updateDest[eidkind] = triggers for i, sheet in single.items(): - updateDest = dest.setdefault(i, {}).setdefault("sheet", {}) + updateDest = dest.setdefault(i, AttrDict()).setdefault("sheet", {}) for eidkind, triggers in sheet.items(): updateDest[eidkind] = triggers for i, tweaks in subdirs.items(): - updateDest = dest.setdefault(i, {}).setdefault("tweaks", {}) + updateDest = dest.setdefault(i, AttrDict()).setdefault("tweaks", {}) combineDir(tweaks, updateDest) - combineDir(sheetTweaked, combined["tweaks"]) + combineDir(sheetTweaked, combined.tweaks) def _compileSheets(self, sheetData): """Compiles the info in tweaked sheets into complete sheets. @@ -1385,31 +1534,44 @@

              Classes

              The tweak may remove triggers from the sheet. We have to adapt the tMap for that. """ - + nameMap = self.nameMap combined = sheetData.combined - compiled = {} + compiled = AttrDict() sheetData.compiled = compiled - console("Compiling the spreadsheets") + def spec(msg): + self.log(None, 0, msg) + + def err(msg): + self.log(True, 0, msg) + + spec("Compiling data") def compileSheet(path, parentData, info, dest): - parentSheet = parentData["sheet"] - sheet = info["sheet"] + parentSheet = parentData.sheet + sheet = info.sheet newSheet = {} - dest["sheet"] = newSheet - parentTMap = parentData.get("tMap", {}) + dest.sheet = newSheet + parentTMap = parentData.tMap or {} newTMap = {} - dest["tMap"] = newTMap + dest.tMap = newTMap + pathRep = f"[{'.'.join(str(i) for i in path)}]" for eidkind, triggers in parentSheet.items(): newSheet[eidkind] = triggers for eidkind, triggers in sheet.items(): - newSheet[eidkind] = triggers + if len(triggers) == 0: + if eidkind in newSheet: + del newSheet[eidkind] + else: + err(f"{pathRep} {nameMap[eidkind][0]} has no triggers") + else: + newSheet[eidkind] = triggers - for trigger in triggers: - newTMap[trigger] = tuple(str(k) for k in path) + for trigger in triggers: + newTMap[trigger] = tuple(str(k) for k in path) for eidkind, triggers in newSheet.items(): for trigger in triggers: @@ -1419,14 +1581,17 @@

              Classes

              def compileDir(path, parentData, info, dest): if "sheet" in info: compileSheet(path, parentData, info, dest) - parentData = dict(sheet=dest["sheet"], tMap=dest["tMap"]) + parentData = AttrDict(sheet=dest.sheet, tMap=dest.tMap) - tweaks = info.get("tweaks", {}) + tweaks = info.tweaks or {} tweakDest = dest.setdefault("tweaks", {}) for k in sorted(tweaks): compileDir( - path + (k,), parentData, tweaks[k], tweakDest.setdefault(k, {}) + path + (k,), + parentData, + tweaks[k], + tweakDest.setdefault(k, AttrDict()), ) compileDir((), combined, combined, compiled) @@ -1473,27 +1638,38 @@

              Classes

              nameMap = self.nameMap compiled = sheetData.compiled - sheetName = self.sheetName - instructions = {} sheetData.instructions = instructions - reportBase = self.reportBase - reportDir = f"{reportBase}/{sheetName}" - reportFile = f"{reportDir}/check.tsv" + def spec(msg): + self.log(None, 0, msg) + + def log(msg): + self.log(False, 0, msg) + + def log1(msg): + self.log(False, 1, msg) + + def log2(msg): + self.log(False, 2, msg) + + def log3(msg): + self.log(False, 3, msg) + + def err(msg): + self.log(True, 0, msg) - console("Checking the spreadsheets") + def err1(msg): + self.log(True, 1, msg) - checkData = ["sheet\tentities\tnotriggers\ttriggers\tambiguous\n"] - ambiData = [] - notrigData = [] + def err2(msg): + self.log(True, 2, msg) - mainNotrigData = set() + spec("Checking triggers ...") def prepareSheet(path, info): - isMain = len(path) == 0 - sheet = info["sheet"] - tMap = info["tMap"] + sheet = info.sheet + tMap = info.tMap sheetR = ".".join(path) sheetRep = f"[{sheetR}]" @@ -1501,20 +1677,11 @@

              Classes

              tPos = collections.defaultdict(lambda: collections.defaultdict(set)) idMap = collections.defaultdict(list) - prepared = dict(tPos=tPos, tMap=tMap) + prepared = AttrDict(tPos=tPos, tMap=tMap) instructions[path] = prepared for eidkind, triggers in sheet.items(): - if len(triggers) == 0: - name = nameMap[eidkind][0] - - if isMain: - mainNotrigData.add(name) - else: - if name not in mainNotrigData: - notrigData.append((name, sheetR)) - for trigger in triggers: triggerT = toTokens(trigger, spaceEscaped=spaceEscaped) triggerSet.add(triggerT) @@ -1524,17 +1691,15 @@

              Classes

              for i, token in enumerate(triggerT): tPos[i][token].add(triggerT) - prepared["idMap"] = { + prepared.idMap = { trigger: eidkinds[0] for (trigger, eidkinds) in idMap.items() } nEnt = len(sheet) nTriggers = sum(len(triggers) for triggers in sheet.values()) noTriggers = sum(1 for triggers in sheet.values() if len(triggers) == 0) - noTrigMsg = "" if noTriggers == 0 else f", {noTriggers} without triggers;" - ambi = 0 - msgs = [] + ambis = collections.defaultdict(list) for trigger, eidkinds in sorted(idMap.items()): if len(eidkinds) <= 1: @@ -1545,60 +1710,61 @@

              Classes

              if path != tPath: continue - msgs.append(f""" trigger '{trigger}' used for:""") - for eidkind in eidkinds: name = nameMap[eidkind][0] - msgs.append(f"\t{name}") - - ambiData.append((trigger, sheetR, name)) + ambis[trigger].append(name) - ambi += 1 + log(f"{sheetRep} {nTriggers} triggers for {nEnt} entities") - ambiMsg = "" if ambi == 0 else f", {ambi} ambiguous" + if noTriggers > 0: + err1(f"{noTriggers} without triggers") - entMsg = f"entities: {nEnt} {noTrigMsg}" - triggerMsg = f"triggers: {nTriggers} {ambiMsg}" + nAmbi = len(ambis) - console(f"{sheetRep:<25}: {entMsg:<35} {triggerMsg}") + if nAmbi > 0: + err1(f"{nAmbi} ambiguous triggers") - if len(msgs): - console("\n".join(msgs)) + for trigger, names in ambis.items(): + err2(trigger) - checkData.append(f"{sheetR}\t{nEnt}\t{noTriggers}\t{nTriggers}\t{ambi}\n") + for name in names: + log3(name) def prepareDir(path, info): if "sheet" in info: prepareSheet(path, info) - tweaks = info.get("tweaks", {}) + tweaks = info.tweaks or {} for k in sorted(tweaks): prepareDir(path + (str(k),), tweaks[k]) prepareDir((), compiled) - with open(reportFile, "w") as rh: - for c in checkData: - rh.write(c) + def _markEntities(self): + """Marks up the members of the inventory as entities. - notrigFile = f"{reportDir}/notriggers.tsv" + The instructions contain the entity identifier and the entity kind that + have to be assigned to the surface forms. - with open(notrigFile, "w") as nh: - nh.write("name\tsheet\n") + The inventory knows where the occurrences of the surface forms are. + If there is no inventory yet, it will be created. + """ + if not self.properlySetup: + return - for name in sorted(mainNotrigData): - nh.write(f"{name}\t\n") - for name, sheet in sorted(notrigData): - nh.write(f"{name}\t{sheet}\n") + sheetName = self.sheetName + sheetData = self.sheets[sheetName] + inventory = sheetData.inventory - ambiFile = f"{reportDir}/ambitriggers.tsv" + newEntities = [] - with open(ambiFile, "w") as ah: - ah.write("trigger\tname\tsheet\n") + for eidkind, entData in inventory.items(): + for trigger, triggerData in entData.items(): + for matches in triggerData.values(): + newEntities.append((eidkind, matches)) - for trigger, sheet, name in sorted(ambiData): - ah.write(f"{trigger}\t{sheet}\t{name}\n") + self._addToSet(newEntities, silent=False) def showSheetsRaw(self, main=False): src = self.getSheetData() @@ -1623,25 +1789,25 @@

              Classes

              tab = " " * level console(f"{tab}{head}") - rng = tweaks.get("rng", {}) + rng = tweaks.rng or {} for b, e in sorted(rng): console(f"{tab} {b}-{e}.xslx") showSheet(rng[(b, e)], tab) - sng = tweaks.get("sng", {}) + sng = tweaks.sng or {} for k in sorted(sng): console(f"{tab} {k}.xslx") showSheet(sng[k], tab) - sdr = tweaks.get("sdr", {}) + sdr = tweaks.sdr or {} for k in sorted(sdr): showDir(k, sdr[k], level + 1) if main: - showSheet(src["main"], "") + showSheet(src.main, "") - showDir("", src["sdr"], 0) + showDir("", src.sdr, 0) def showSheetsCombined(self, main=False): src = self.getSheetData() @@ -1668,9 +1834,9 @@

              Classes

              if "sheet" in info: if main or level > 0: - showSheet(info["sheet"], tab) + showSheet(info.sheet, tab) - tweaks = info.get("tweaks", {}) + tweaks = info.tweaks or {} for k in sorted(tweaks): showDir(k, tweaks[k], level + 1) @@ -1682,8 +1848,8 @@

              Classes

              src = self.compiled def showSheet(info, tab): - sheet = info["sheet"] - tMap = info["tMap"] + sheet = info.sheet + tMap = info.tMap for eidkind, triggers in sorted(sheet.items()): triggerSources = {tMap[t] for t in triggers} @@ -1718,7 +1884,7 @@

              Classes

              if main or level > 0: showSheet(info, tab) - tweaks = info.get("tweaks", {}) + tweaks = info.tweaks or {} for k in sorted(tweaks): showDir(k, tweaks[k], level + 1) @@ -1758,6 +1924,20 @@

              Instance variables

          Methods

          +
          +def clearLog(self) +
          +
          +
          +
          + +Expand source code +Browse git + +
          def clearLog(self):
          +    self.logData.clear()
          +
          +
          def fromSourceSheet(self)
          @@ -1775,7 +1955,7 @@

          Methods

          Expand source code -Browse git +Browse git
          def fromSourceSheet(self):
               """Loads a ner sheet from source.
          @@ -1794,6 +1974,7 @@ 

          Methods

          if not self.properlySetup: return None + logData = self.logData sheetName = self.sheetName if sheetName is None: @@ -1806,10 +1987,6 @@

          Methods

          sheetDir = self.sheetDir sheetFile = f"{sheetDir}/{sheetName}.xlsx" - reportBase = self.reportBase - reportDir = f"{reportBase}/{sheetName}" - initTree(reportDir, fresh=False) - def timeXls(sheetRela): sep = "/" if sheetRela else "" sheetPath = f"{sheetDir}/{sheetName}{sep}{sheetRela}.xlsx" @@ -1836,11 +2013,18 @@

          Methods

          or (fileExists(sheetFile) and sheetData.dateLoaded < mT) ): changed = True + self.clearLog() self._readSheets(sheetData) self._combineSheets(sheetData) self._compileSheets(sheetData) self._prepareSheets(sheetData) sheetData.dateLoaded = time.time() + self.writeLog() + else: + if len(logData) == 0: + self.showLog() + else: + self.readLog() return changed
          @@ -1853,11 +2037,10 @@

          Methods

          Expand source code -Browse git +Browse git
          def getSheetData(self):
          -    """Deliver the current sheet.
          -    """
          +    """Deliver the current sheet."""
               sheetName = self.sheetName
           
               if sheetName is None:
          @@ -1876,11 +2059,10 @@ 

          Methods

          Expand source code -Browse git +Browse git
          def loadSheetData(self):
          -    """Loads the current ner sheet into memory, if there is one.
          -    """
          +    """Loads the current ner sheet into memory, if there is one."""
               if not self.properlySetup:
                   return
           
          @@ -1897,6 +2079,26 @@ 

          Methods

          self.processSheet(changed)
          +
          +def log(self, isError, indent, msg) +
          +
          +
          +
          + +Expand source code +Browse git + +
          def log(self, isError, indent, msg):
          +    browse = self.browse
          +    logData = self.logData
          +
          +    logData.append((isError, indent, msg))
          +
          +    if not browse:
          +        consoleLine(isError, indent, msg)
          +
          +
          def processSheet(self, changed)
          @@ -1924,7 +2126,7 @@

          Parameters

          Expand source code -Browse git +Browse git
          def processSheet(self, changed):
               """Generates derived data structures out of the source sheet.
          @@ -1969,19 +2171,52 @@ 

          Parameters

          or dateLoaded is not None and dateProcessed < dateLoaded ): - if not browse: app = self.app app.indent(reset=True) app.info("Looking up occurrences of many candidates ...") self.findOccs() - self.markEntities() - sheetData.dateProcessed = time.time() if not browse: app.info("done") - self.reportHits()
          + self.reportHits() + + self._markEntities() + sheetData.dateProcessed = time.time()
          +
          + +
          +def readLog(self) +
          +
          +
          +
          + +Expand source code +Browse git + +
          def readLog(self):
          +    browse = self.browse
          +    logData = self.logData
          +    setName = self.setName
          +    annoDir = self.annoDir
          +    setDir = f"{annoDir}/{setName}"
          +    logFile = f"{setDir}/excel.tsv"
          +
          +    if fileExists(logFile):
          +        self.clearLog()
          +
          +        with open(logFile) as fh:
          +            for line in fh:
          +                fields = line.rstrip("\n").split("\t")
          +                isError = None if fields[0] == "special" else fields[0] == "error"
          +                indent = int(fields[1])
          +                msg = fields[2]
          +                logData.append((isError, indent, msg))
          +
          +                if not browse:
          +                    consoleLine(isError, indent, msg)
          @@ -1994,7 +2229,7 @@

          Parameters

          Expand source code -Browse git +Browse git
          def readSheets(self):
               """Read the list current ner sheets (again).
          @@ -2024,7 +2259,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def setSheet(self, newSheet):
               """Switch to a named ner sheet.
          @@ -2043,10 +2278,6 @@ 

          Parameters

          sheetName = self.sheetName - if not newSheet: - self.sheetName = None - return - sheetNames = self.sheetNames sheetDir = self.sheetDir sheetFile = f"{sheetDir}/{newSheet}.xlsx" @@ -2056,10 +2287,13 @@

          Parameters

          self.console(f"Ner sheet {newSheet} ({sheetFile}) does not exist") return + self.setSet("" if newSheet is None else f".{newSheet}") + if newSheet != sheetName: sheetName = newSheet self.sheetName = sheetName - self.loadSheetData()
          + + self.loadSheetData()
          @@ -2070,7 +2304,7 @@

          Parameters

          Expand source code -Browse git +Browse git
          def showInstructions(self):
               src = self.getSheetData()
          @@ -2083,6 +2317,25 @@ 

          Parameters

          console("\n".join(f"{path}" for path in instructions))
          +
          +def showLog(self) +
          +
          +
          +
          + +Expand source code +Browse git + +
          def showLog(self):
          +    browse = self.browse
          +    logData = self.logData
          +
          +    if not browse:
          +        for x in logData:
          +            consoleLine(*x)
          +
          +
          def showSheetsCombined(self, main=False)
          @@ -2091,7 +2344,7 @@

          Parameters

          Expand source code -Browse git +Browse git
          def showSheetsCombined(self, main=False):
               src = self.getSheetData()
          @@ -2118,9 +2371,9 @@ 

          Parameters

          if "sheet" in info: if main or level > 0: - showSheet(info["sheet"], tab) + showSheet(info.sheet, tab) - tweaks = info.get("tweaks", {}) + tweaks = info.tweaks or {} for k in sorted(tweaks): showDir(k, tweaks[k], level + 1) @@ -2136,15 +2389,15 @@

          Parameters

          Expand source code -Browse git +Browse git
          def showSheetsCompiled(self, main=False):
               nameMap = self.nameMap
               src = self.compiled
           
               def showSheet(info, tab):
          -        sheet = info["sheet"]
          -        tMap = info["tMap"]
          +        sheet = info.sheet
          +        tMap = info.tMap
           
                   for eidkind, triggers in sorted(sheet.items()):
                       triggerSources = {tMap[t] for t in triggers}
          @@ -2179,7 +2432,7 @@ 

          Parameters

          if main or level > 0: showSheet(info, tab) - tweaks = info.get("tweaks", {}) + tweaks = info.tweaks or {} for k in sorted(tweaks): showDir(k, tweaks[k], level + 1) @@ -2195,7 +2448,7 @@

          Parameters

          Expand source code -Browse git +Browse git
          def showSheetsRaw(self, main=False):
               src = self.getSheetData()
          @@ -2220,25 +2473,50 @@ 

          Parameters

          tab = " " * level console(f"{tab}{head}") - rng = tweaks.get("rng", {}) + rng = tweaks.rng or {} for b, e in sorted(rng): console(f"{tab} {b}-{e}.xslx") showSheet(rng[(b, e)], tab) - sng = tweaks.get("sng", {}) + sng = tweaks.sng or {} for k in sorted(sng): console(f"{tab} {k}.xslx") showSheet(sng[k], tab) - sdr = tweaks.get("sdr", {}) + sdr = tweaks.sdr or {} for k in sorted(sdr): showDir(k, sdr[k], level + 1) if main: - showSheet(src["main"], "") + showSheet(src.main, "") - showDir("", src["sdr"], 0)
          + showDir("", src.sdr, 0)
          +
          + +
          +def writeLog(self) +
          +
          +
          +
          + +Expand source code +Browse git + +
          def writeLog(self):
          +    logData = self.logData
          +    setName = self.setName
          +    annoDir = self.annoDir
          +    setDir = f"{annoDir}/{setName}"
          +    logFile = f"{setDir}/excel.tsv"
          +
          +    with open(logFile, "w") as fh:
          +        for fields in logData:
          +            mode = (
          +                "special" if fields[0] is None else "error" if fields[0] else "info"
          +            )
          +            fh.write(f"{mode}\t{fields[1]}\t{fields[2]}\n")
          @@ -2313,19 +2591,24 @@

          Index

        • Sheets

        diff --git a/tf/browser/ner/show.html b/tf/browser/ner/show.html index 7edac9d54..695b25dec 100644 --- a/tf/browser/ner/show.html +++ b/tf/browser/ner/show.html @@ -34,7 +34,7 @@

        Module tf.browser.ner.show

        Expand source code -Browse git +Browse git
        """Rendering of corpus extracts with annotations.
         
        @@ -292,7 +292,7 @@ 

        Module tf.browser.ner.show

        browse = self.browse setData = self.getSetData() - setName = self.setName + setIsRo = self.setIsRo afterv = self.getAfter() sectionHead = self.sectionHead @@ -330,16 +330,16 @@

        Module tf.browser.ner.show

        nBshown += 1 charPos = 0 - if setName: + if setIsRo: + allMatches = set(chain.from_iterable(matches)) + else: allMatches = set() endMatches = set() + for match in matches: allMatches |= set(match) endMatches.add(match[-1]) - else: - allMatches = set(chain.from_iterable(matches)) - headContent = H.span( H.span(sectionHead(b), cls="bhl ltr", title="show context"), cls=f"bh {ltr}", @@ -398,7 +398,7 @@

        Module tf.browser.ner.show

        hlClasses += f" {style} " if style else "" hlClass = dict(cls=hlClasses) if hlClasses else {} - endQueried = setName and t in endMatches + endQueried = (not setIsRo) and t in endMatches excl = "x" if t in excludedTokens else "v" nodeRep = H.span(str(t), cls="nd") if withNodes else "" @@ -449,7 +449,7 @@

        Classes

        Expand source code -Browse git +Browse git
        class Show:
             def showEntityOverview(self):
        @@ -684,7 +684,7 @@ 

        Classes

        browse = self.browse setData = self.getSetData() - setName = self.setName + setIsRo = self.setIsRo afterv = self.getAfter() sectionHead = self.sectionHead @@ -722,16 +722,16 @@

        Classes

        nBshown += 1 charPos = 0 - if setName: + if setIsRo: + allMatches = set(chain.from_iterable(matches)) + else: allMatches = set() endMatches = set() + for match in matches: allMatches |= set(match) endMatches.add(match[-1]) - else: - allMatches = set(chain.from_iterable(matches)) - headContent = H.span( H.span(sectionHead(b), cls="bhl ltr", title="show context"), cls=f"bh {ltr}", @@ -790,7 +790,7 @@

        Classes

        hlClasses += f" {style} " if style else "" hlClass = dict(cls=hlClasses) if hlClasses else {} - endQueried = setName and t in endMatches + endQueried = (not setIsRo) and t in endMatches excl = "x" if t in excludedTokens else "v" nodeRep = H.span(str(t), cls="nd") if withNodes else "" @@ -888,7 +888,7 @@

        Returns

        Expand source code -Browse git +Browse git
        def showContent(
             self,
        @@ -968,7 +968,7 @@ 

        Returns

        browse = self.browse setData = self.getSetData() - setName = self.setName + setIsRo = self.setIsRo afterv = self.getAfter() sectionHead = self.sectionHead @@ -1006,16 +1006,16 @@

        Returns

        nBshown += 1 charPos = 0 - if setName: + if setIsRo: + allMatches = set(chain.from_iterable(matches)) + else: allMatches = set() endMatches = set() + for match in matches: allMatches |= set(match) endMatches.add(match[-1]) - else: - allMatches = set(chain.from_iterable(matches)) - headContent = H.span( H.span(sectionHead(b), cls="bhl ltr", title="show context"), cls=f"bh {ltr}", @@ -1074,7 +1074,7 @@

        Returns

        hlClasses += f" {style} " if style else "" hlClass = dict(cls=hlClasses) if hlClasses else {} - endQueried = setName and t in endMatches + endQueried = (not setIsRo) and t in endMatches excl = "x" if t in excludedTokens else "v" nodeRep = H.span(str(t), cls="nd") if withNodes else "" @@ -1159,7 +1159,7 @@

        Returns

        Expand source code -Browse git +Browse git
        def showEntities(
             self, activeEntity=None, sortKey=None, sortDir=None, cutOffFreq=None
        @@ -1297,7 +1297,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def showEntityOverview(self):
             """Generates HTML for an overview of the entities.
        diff --git a/tf/browser/ner/web.html b/tf/browser/ner/web.html
        index 5426af8fa..d93bd5fe3 100644
        --- a/tf/browser/ner/web.html
        +++ b/tf/browser/ner/web.html
        @@ -34,7 +34,7 @@ 

        Module tf.browser.ner.web

        Expand source code -Browse git +Browse git
        """Flask sub web app in the TF browser.
         
        @@ -169,7 +169,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def factory(web):
             """A sub web app, to be inserted into the TF browser web app.
        diff --git a/tf/browser/serve.html b/tf/browser/serve.html
        index cf7900d10..4278319db 100644
        --- a/tf/browser/serve.html
        +++ b/tf/browser/serve.html
        @@ -37,7 +37,7 @@ 

        Dress TF nodes up for serving
        Expand source code -Browse git +Browse git
        """
         # Dress TF nodes up for serving on the web
        @@ -531,7 +531,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def serveAll(web, anything):
             aContext = web.context
        @@ -662,7 +662,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def serveDownload(web, jobOnly):
             aContext = web.context
        @@ -761,7 +761,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def serveExport(web):
             aContext = web.context
        @@ -835,7 +835,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def servePassage(web, getx=None):
             kernelApi = web.kernelApi
        @@ -885,7 +885,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def serveQuery(web, getx=None, asDict=False):
             kernelApi = web.kernelApi
        @@ -978,7 +978,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def serveTable(web, kind, getx=None, asDict=False):
             kernelApi = web.kernelApi
        diff --git a/tf/browser/servelib.html b/tf/browser/servelib.html
        index 8835832f9..7ab4c5fc6 100644
        --- a/tf/browser/servelib.html
        +++ b/tf/browser/servelib.html
        @@ -39,7 +39,7 @@ 

        About

        Expand source code -Browse git +Browse git
        """
         # Common Server Related Functions
        @@ -320,7 +320,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def batchAround(nResults, position, batch):
             halfBatch = int((batch + 1) / 2)
        @@ -342,7 +342,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def getAbout(colophon, header, provenance, form):
             return f"""
        @@ -396,7 +396,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def getFormData(interfaceDefaults):
             """Get form data.
        @@ -557,7 +557,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def getInt(x, default=1):
             if len(x) > 15:
        @@ -575,7 +575,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def zipTables(csvs, tupleResultsX, queryResultsX, about, form):
             appName = form["appName"]
        diff --git a/tf/browser/start.html b/tf/browser/start.html
        index 7cd8eb980..cd511c46a 100644
        --- a/tf/browser/start.html
        +++ b/tf/browser/start.html
        @@ -89,7 +89,7 @@ 

        Implementation notes

        Expand source code -Browse git +Browse git
        """
         # Start the TF browser
        @@ -368,7 +368,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def bMsg(url):
             return f"\n\tOpen a webbrowser and navigate to url {url}\n"
        @@ -382,7 +382,7 @@

        Functions

        Expand source code -Browse git +Browse git
        def main(cargs=sys.argv[1:]):
             console(BANNER)
        @@ -441,7 +441,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def startBrowser(url, forceChrome, debug):
             opened = False
        diff --git a/tf/browser/web.html b/tf/browser/web.html
        index a8bc01397..d5584e34b 100644
        --- a/tf/browser/web.html
        +++ b/tf/browser/web.html
        @@ -114,7 +114,7 @@ 

        JavaScript

        Expand source code -Browse git +Browse git
        """
         # Web interface
        @@ -407,7 +407,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def factory(web):
             app = Flask(__name__)
        @@ -495,7 +495,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def runWeb(webapp, debug, portWeb):
             run_simple(
        @@ -519,7 +519,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def setup(debug, *args):
             appSpecs = argApp(args, False)
        @@ -595,7 +595,7 @@ 

        Classes

        Expand source code -Browse git +Browse git
        class Web:
             def __init__(self, kernelApi):
        @@ -619,7 +619,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def console(self, msg):
             if self.debug:
        diff --git a/tf/browser/wrap.html b/tf/browser/wrap.html
        index ea871aa16..b1a1fe60a 100644
        --- a/tf/browser/wrap.html
        +++ b/tf/browser/wrap.html
        @@ -33,7 +33,7 @@ 

        Wrap material into HTML

        Expand source code -Browse git +Browse git
        """
         # Wrap material into HTML
        @@ -592,7 +592,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def pageLinks(nResults, position, spread=10):
             """Provide navigation links for results sets, big or small.
        @@ -675,7 +675,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def passageLinks(passages, sec0Type, sec0, sec1, tillLevel):
             """Provide navigation links for passages,
        @@ -728,7 +728,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def wrapColorMap(form):
             """Wraps the color map for query result highlighting into HTML.
        @@ -813,7 +813,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def wrapEColorMap(form):
             """Wraps the edge color map for edge highlighting into HTML.
        @@ -922,7 +922,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def wrapOptions(context, form):
             """Wraps the boolean options, including the app-specific ones, into HTML."""
        @@ -962,7 +962,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def wrapProvenance(form, provenance, setNames):
             utc_offset_sec = time.altzone if time.localtime().tm_isdst else time.timezone
        @@ -1138,7 +1138,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def wrapSelect(option, allowedValues, value, group, item, multiple):
             """Provides a buttoned chooser for the node types.
        diff --git a/tf/capable.html b/tf/capable.html
        index c0f243d28..56ae87733 100644
        --- a/tf/capable.html
        +++ b/tf/capable.html
        @@ -86,7 +86,7 @@ 

        Optional dependencies

        Expand source code -Browse git +Browse git
        """Dependency management.
         
        @@ -500,7 +500,7 @@ 

        Classes

        Expand source code -Browse git +Browse git
        class Capable:
             """Import modules for back-end communication if possible.
        @@ -615,7 +615,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def can(self, extra):
             if extra in {"github", "gitlab"}:
        @@ -646,7 +646,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def load(self, module):
             modules = self.modules
        @@ -671,7 +671,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def loadFrom(self, module, *members):
             loaded = self.load(module)
        @@ -692,7 +692,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def tryImport(self, *extras):
             backendProviders = self.backendProviders
        @@ -771,7 +771,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        class CheckImport:
             def __init__(self, *modules, optional=False):
        @@ -969,7 +969,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def importGet(self):
             """Delivers the imported modules.
        @@ -1008,7 +1008,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def importOK(self, hint=False):
             """Reports the result of the import attempts.
        diff --git a/tf/cheatsheet.html b/tf/cheatsheet.html
        index 7634eed85..10ca3fb46 100644
        --- a/tf/cheatsheet.html
        +++ b/tf/cheatsheet.html
        @@ -56,6 +56,14 @@ 

        Initialization, conf

        App.load()

        +
        A.featureTypes(show=True)
        +
        +
        +

        show for which types each feature is defined

        +
        +
        +

        App.featureTypes()

        +
        A.showContext(...)
         
        @@ -1661,7 +1669,7 @@

        Command-line tools

        Expand source code -Browse git +Browse git
        """
         .. include:: docs/main/cheatsheet.md
        diff --git a/tf/clean.html b/tf/clean.html
        index fe4d38670..14475e93f 100644
        --- a/tf/clean.html
        +++ b/tf/clean.html
        @@ -40,7 +40,7 @@ 

        Clean

        Expand source code -Browse git +Browse git
        """
         # Clean
        @@ -207,7 +207,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def clean(tfd=True, backend=None, dry=True, specific=None, current=False):
             """Clean up older compressed `.tfx` files.
        @@ -293,7 +293,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def err(msg):
             """Write to standard error output immediately."""
        @@ -309,7 +309,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def out(msg):
             """Write to standard normal output immediately."""
        diff --git a/tf/client/index.html b/tf/client/index.html
        index f782aa69d..27183a7ca 100644
        --- a/tf/client/index.html
        +++ b/tf/client/index.html
        @@ -57,7 +57,7 @@ 

        Acknowledgments

        Expand source code -Browse git +Browse git
        """
         # Layered Search
        diff --git a/tf/client/make/build.html b/tf/client/make/build.html
        index f357a4dff..698569b39 100644
        --- a/tf/client/make/build.html
        +++ b/tf/client/make/build.html
        @@ -81,7 +81,7 @@ 

        Commands

        Expand source code -Browse git +Browse git
        """
         # Usage
        @@ -1497,7 +1497,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def console(*args, error=False):
             device = sys.stderr if error else sys.stdout
        @@ -1513,7 +1513,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def invertMap(legend):
             return (
        @@ -1533,7 +1533,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def main():
             Args = readArgsLegacy()
        @@ -1594,7 +1594,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def makeSearchClients(dataset, folder, appFolder, backend=None, dataDir=None):
             DEBUG_STATE = "off"
        @@ -1640,7 +1640,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def readArgsLegacy():
             class Args:
        @@ -1753,7 +1753,7 @@ 

        Classes

        Expand source code -Browse git +Browse git
        class Make:
             def __init__(
        @@ -2862,7 +2862,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def adjustDebug(self):
             C = self.C
        @@ -2894,7 +2894,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def adjustVersion(self):
             C = self.C
        @@ -2917,7 +2917,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def compress(self, data):
             sets = {}
        @@ -2944,7 +2944,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def config(self):
             C = self.C
        @@ -3220,7 +3220,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def doCommand(self, command):
             if command == "serve":
        @@ -3257,7 +3257,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def dumpConfig(self):
             C = self.C
        @@ -3283,7 +3283,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def dumpCorpus(self):
             C = self.C
        @@ -3412,7 +3412,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def getAllClients(self):
             C = self.C
        @@ -3437,7 +3437,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def getDebugs(self):
             C = self.C
        @@ -3470,7 +3470,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def importMake(self, c=None):
             client = self.client
        @@ -3510,7 +3510,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def incVersion(self):
             C = self.C
        @@ -3530,7 +3530,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def loadTf(self):
             C = self.C
        @@ -3552,7 +3552,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def make(self):
             self.makeConfig()
        @@ -3586,7 +3586,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def makeClient(self):
             """
        @@ -3670,7 +3670,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def makeClientSettings(self):
             C = self.C
        @@ -3814,7 +3814,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def makeCombined(self):
             C = self.C
        @@ -3884,7 +3884,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def makeConfig(self):
             if not getattr(self, "A", None):
        @@ -3902,7 +3902,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def makeCorpus(self):
             if not getattr(self, "A", None):
        @@ -3929,7 +3929,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def makeHtml(self):
             C = self.C
        @@ -4010,7 +4010,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def makeLinks(self):
             C = self.C
        @@ -4041,7 +4041,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def publish(self, allClients=True):
             C = self.C
        @@ -4074,7 +4074,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def replaceDebug(self, mask, value):
             def subVersion(match):
        @@ -4091,7 +4091,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def serve(self):
             dataset = self.dataset
        @@ -4134,7 +4134,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def ship(self, publish=True):
             self.adjustVersion()
        @@ -4155,7 +4155,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def showDebug(self):
             debugInfo = self.getDebugs()
        @@ -4175,7 +4175,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def showVersion(self):
             C = self.C
        @@ -4192,7 +4192,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def zipApp(self):
             C = self.C
        diff --git a/tf/client/make/gh.html b/tf/client/make/gh.html
        index 7d66dbbe9..3c3d90bbe 100644
        --- a/tf/client/make/gh.html
        +++ b/tf/client/make/gh.html
        @@ -31,7 +31,7 @@ 

        Module tf.client.make.gh

        Expand source code -Browse git +Browse git
        import sys
         import os
        @@ -210,7 +210,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def console(*args):
             sys.stdout.write(" ".join(args) + "\n")
        @@ -225,7 +225,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def deploy(org, repo):
             (result, error) = _ghp_import()
        diff --git a/tf/client/make/help.html b/tf/client/make/help.html
        index 4ce1379b1..273a5ecbf 100644
        --- a/tf/client/make/help.html
        +++ b/tf/client/make/help.html
        @@ -31,7 +31,7 @@ 

        Module tf.client.make.help

        Expand source code -Browse git +Browse git
        HELP = """
         tf-make [--backend={backend} {org}/{repo} serve {folder}
        diff --git a/tf/client/make/index.html b/tf/client/make/index.html
        index 53e7637e2..dd479064d 100644
        --- a/tf/client/make/index.html
        +++ b/tf/client/make/index.html
        @@ -32,7 +32,7 @@ 

        Module tf.client.make

        Expand source code -Browse git +Browse git
        """
         The search app make program
        diff --git a/tf/convert/addnlp.html b/tf/convert/addnlp.html
        index a5f953cc0..1fb7a06da 100644
        --- a/tf/convert/addnlp.html
        +++ b/tf/convert/addnlp.html
        @@ -114,7 +114,7 @@ 

        Examples

        Expand source code -Browse git +Browse git
        """Add data from an NLP pipeline.
         
        @@ -1760,7 +1760,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def main():
             (good, tasks, params, flags) = readArgs("tf-addnlp", HELP, TASKS, PARAMS, FLAGS)
        @@ -1859,7 +1859,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        class NLPipeline(CheckImport):
             def __init__(
        @@ -3296,7 +3296,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def generatePlain(self):
             """Generates a plain text out of a data source.
        @@ -3529,7 +3529,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def getElementInfo(self, verbose=None):
             """Analyse the schema.
        @@ -3653,7 +3653,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def ingest(
             self,
        @@ -4176,7 +4176,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def ingestNlpOutput(self, positions, tkStream, sentenceStream, entityStream):
             """Ingests NLP output such as tokens in a dataset. Tokens become the new slots.
        @@ -4511,7 +4511,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def lingo(self, *args, **kwargs):
             if not self.importOK():
        @@ -4541,7 +4541,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def loadApp(self, app=None, verbose=None):
             """Loads a given TF app or loads the TF app based on the working directory.
        @@ -4650,7 +4650,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def task(
             self,
        diff --git a/tf/convert/app/app.html b/tf/convert/app/app.html
        index 49069a966..1d9cf8546 100644
        --- a/tf/convert/app/app.html
        +++ b/tf/convert/app/app.html
        @@ -31,7 +31,7 @@ 

        Module tf.convert.app.app

        Expand source code -Browse git +Browse git
        import types
         from tf.advanced.app import App
        @@ -91,7 +91,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def fmt_layout(app, n, **kwargs):
             return app._wrapHtml(n)
        @@ -146,7 +146,7 @@

        Parameters

        Expand source code -Browse git +Browse git
        class TfApp(App):
             def __init__(app, *args, **kwargs):
        @@ -187,6 +187,7 @@ 

        Inherited members

      • App:
        • context
        • +
        • featureTypes
        • hoist
        • load
        • reinit
        • diff --git a/tf/convert/helpers.html b/tf/convert/helpers.html index 01916f0ae..e6c747cc0 100644 --- a/tf/convert/helpers.html +++ b/tf/convert/helpers.html @@ -31,7 +31,7 @@

          Module tf.convert.helpers

          Expand source code -Browse git +Browse git
          import re
           from textwrap import dedent
          @@ -835,7 +835,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def checkModel(kind, thisModel, verbose):
               modelDefault = (
          @@ -925,7 +925,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def getWhites(text):
               match = W_BEFORE.match(text)
          @@ -997,7 +997,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def lookupSource(cv, cur, tokenAsSlot, specs):
               """Looks up information from the current XML stack.
          @@ -1116,7 +1116,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def matchModel(properties, tag, atts):
               if tag == properties["element"]:
          @@ -1144,7 +1144,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def repTokens(tokens):
               text = []
          @@ -1161,7 +1161,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def setUp(kind):
               helpText = f"""
          @@ -1214,7 +1214,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def tokenize(line):
               tokens = []
          @@ -1242,7 +1242,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def tweakTrans(
               template,
          diff --git a/tf/convert/index.html b/tf/convert/index.html
          index 817b257a4..43cb8abc9 100644
          --- a/tf/convert/index.html
          +++ b/tf/convert/index.html
          @@ -39,7 +39,7 @@ 

          Various forms of data interchange

          Expand source code -Browse git +Browse git
          """
           # Various forms of data interchange
          diff --git a/tf/convert/makewatm.html b/tf/convert/makewatm.html
          index 4a7bb0424..f70052d91 100644
          --- a/tf/convert/makewatm.html
          +++ b/tf/convert/makewatm.html
          @@ -31,7 +31,7 @@ 

          Module tf.convert.makewatm

          Expand source code -Browse git +Browse git
          import sys
           from textwrap import dedent
          @@ -515,7 +515,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          class MakeWATM:
               """Base class for running conversions to WATM.
          @@ -939,7 +939,7 @@ 

          Methods

          Expand source code -Browse git +Browse git
          def doTask_page2tf(self):
               good = self.good
          @@ -996,7 +996,7 @@ 

          Methods

          Expand source code -Browse git +Browse git
          def doTask_tei2tf(self):
               good = self.good
          @@ -1086,7 +1086,7 @@ 

          Methods

          Expand source code -Browse git +Browse git
          def doTask_watm(self):
               good = self.good
          @@ -1130,7 +1130,7 @@ 

          Methods

          Expand source code -Browse git +Browse git
          def doTask_watms(self):
               good = self.good
          @@ -1160,7 +1160,7 @@ 

          Methods

          Expand source code -Browse git +Browse git
          def main(self, cmdLine=None, cargs=sys.argv[1:]):
               FLAGS = self.FLAGS
          @@ -1232,7 +1232,7 @@ 

          Methods

          Expand source code -Browse git +Browse git
          def prepareRun(self, tasks):
               return
          @@ -1246,7 +1246,7 @@

          Methods

          Expand source code -Browse git +Browse git
          def run(self, tasks):
               TASKS = self.TASKS
          @@ -1269,7 +1269,7 @@ 

          Methods

          Expand source code -Browse git +Browse git
          def setOptions(
               self,
          diff --git a/tf/convert/mql.html b/tf/convert/mql.html
          index 6aaf9f58f..8f0e6514b 100644
          --- a/tf/convert/mql.html
          +++ b/tf/convert/mql.html
          @@ -140,7 +140,7 @@ 

          Naming of features in MQL

          Expand source code -Browse git +Browse git
          """
           # MQL
          @@ -1223,7 +1223,7 @@ 

          See Also

          Expand source code -Browse git +Browse git
          def exportMQL(app, mqlDb, exportDir=None):
               """Exports the complete TF dataset into single MQL database.
          @@ -1340,7 +1340,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def importMQL(mqlFile, saveDir, silent=None, slotType=None, otext=None, meta=None):
               """Converts an MQL database dump to a TF dataset.
          @@ -1426,7 +1426,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def makeuni(match):
               """Make proper UNICODE of a text that contains byte escape codes
          @@ -1444,7 +1444,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def parseMql(mqlFile, tmObj):
               info = tmObj.info
          @@ -1658,7 +1658,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def tfFromData(tmObj, objectTypes, tables, nodeF, edgeF, slotType, otext, meta):
               info = tmObj.info
          @@ -1787,7 +1787,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def tfFromMql(mqlFile, tmObj, slotType=None, otext=None, meta=None):
               """Generate TF from MQL
          @@ -1819,7 +1819,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def uni(line):
               return uniscan.sub(makeuni, line)
          @@ -1839,7 +1839,7 @@

          Classes

          Expand source code -Browse git +Browse git
          class MQL:
               def __init__(self, app, mqlDb, exportDir, silent=SILENT_D):
          @@ -2240,7 +2240,7 @@ 

          Methods

          Expand source code -Browse git +Browse git
          def write(self):
               silent = self.silent
          diff --git a/tf/convert/pagexml.html b/tf/convert/pagexml.html
          index b190ff395..60d1e73e2 100644
          --- a/tf/convert/pagexml.html
          +++ b/tf/convert/pagexml.html
          @@ -31,7 +31,7 @@ 

          Module tf.convert.pagexml

          Expand source code -Browse git +Browse git
          import sys
           from subprocess import run
          @@ -1113,7 +1113,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def diverge(cv, s, rtx, rsp, ltx, lsp):
               if ltx != rtx:
          @@ -1130,7 +1130,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def emptySlot(cv):
               s = cv.slot()
          @@ -1145,7 +1145,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def linebreakSlot(cv):
               s = cv.slot()
          @@ -1160,7 +1160,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def main():
               (good, tasks, params, flags) = readArgs(
          @@ -1183,7 +1183,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def setUp():
               helpText = """
          @@ -1234,7 +1234,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def tokenLogic(cv, s, token, hangover, isFirst, isSecondLast, isLast):
               (rtx, rsp) = token
          @@ -1299,7 +1299,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def walkObject(cv, cur, xObj):
               """Internal function to deal with a single element.
          @@ -1488,7 +1488,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          class PageXML(CheckImport):
               def __init__(
          @@ -2367,7 +2367,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def appTask(self):
               """Implementation of the "app" task.
          @@ -2551,7 +2551,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def browseTask(self):
               """Implementation of the "browse" task.
          @@ -2615,7 +2615,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def convertTask(self):
               """Implementation of the "convert" task.
          @@ -2698,7 +2698,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def getConverter(self, doc):
               """Initializes a converter.
          @@ -2737,7 +2737,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def getDirector(self, doc, docMeta, pageSource, pageFiles):
               """Factory for the director function.
          @@ -2823,7 +2823,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def loadTask(self):
               """Implementation of the "load" task.
          @@ -2914,7 +2914,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def task(
               self,
          diff --git a/tf/convert/pandas.html b/tf/convert/pandas.html
          index abda080ee..d9745f45d 100644
          --- a/tf/convert/pandas.html
          +++ b/tf/convert/pandas.html
          @@ -61,7 +61,7 @@ 

          Examples

          Expand source code -Browse git +Browse git
          """
           # Export a TF dataset to a `pandas` data frame.
          @@ -440,7 +440,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def exportPandas(app, inTypes=None, exportDir=None):
               """Export a currently loaded TF dataset to `pandas`.
          diff --git a/tf/convert/recorder.html b/tf/convert/recorder.html
          index 06e7942b4..39d67d326 100644
          --- a/tf/convert/recorder.html
          +++ b/tf/convert/recorder.html
          @@ -185,7 +185,7 @@ 

          Usage

          Expand source code -Browse git +Browse git
          """
           # Recorder
          @@ -964,7 +964,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          class Recorder:
               def __init__(self, api=None):
          @@ -1633,7 +1633,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def add(self, string, empty=ZWJ):
               """Add text to the accumulator.
          @@ -1671,7 +1671,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def end(self, n):
               """End a node.
          @@ -1722,7 +1722,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def iPositions(self, byType=False, logical=True, asEntries=False):
               """Get the character positions as mapping from nodes.
          @@ -1830,7 +1830,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def makeFeatures(self, featurePath, headers=True):
               """Read a tab-separated file of annotation data and convert it to features.
          @@ -1935,7 +1935,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def positions(self, byType=False, simple=False):
               """Get the node positions as mapping from character positions.
          @@ -2098,7 +2098,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def rPositions(self, acceptMaterialOutsideNodes=False):
               """Get the first textual position for each node
          @@ -2267,7 +2267,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def read(self, textPath, posPath=None):
               """Read recorder information from disk.
          @@ -2317,7 +2317,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def start(self, n):
               """Start a node.
          @@ -2345,7 +2345,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def text(self):
               """Get the accumulated text.
          @@ -2404,7 +2404,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def write(
               self, textPath, inverted=False, posPath=None, byType=False, optimize=True
          diff --git a/tf/convert/tei.html b/tf/convert/tei.html
          index 954f6f6e0..34e81d694 100644
          --- a/tf/convert/tei.html
          +++ b/tf/convert/tei.html
          @@ -452,7 +452,7 @@ 

          Examples

          Expand source code -Browse git +Browse git
          """
           # TEI import
          @@ -5118,7 +5118,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def getRefs(tag, atts, xmlFile):
               refAtt = REFERENCING.get(tag, None)
          @@ -5148,7 +5148,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def main():
               (good, tasks, params, flags) = readArgs(
          @@ -5171,7 +5171,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def makeCssInfo():
               """Make the CSS info for the style sheet."""
          @@ -5319,7 +5319,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          class TEI(CheckImport):
               def __init__(
          @@ -9141,7 +9141,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def appTask(self, tokenBased=False):
               """Implementation of the "app" task.
          @@ -9530,7 +9530,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def browseTask(self):
               """Implementation of the "browse" task.
          @@ -9598,7 +9598,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def checkTask(self):
               """Implementation of the "check" task.
          @@ -10318,7 +10318,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def convertTask(self):
               """Implementation of the "convert" task.
          @@ -10405,7 +10405,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def getConverter(self):
               """Initializes a converter.
          @@ -10446,7 +10446,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def getDirector(self):
               """Factory for the director function.
          @@ -12078,7 +12078,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def getParser(self):
               """Configure the LXML parser.
          @@ -12113,7 +12113,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def getSwitches(self, xmlPath):
               verbose = self.verbose
          @@ -12179,7 +12179,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def getXML(self):
               """Make an inventory of the TEI source files.
          @@ -12277,7 +12277,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def loadTask(self):
               """Implementation of the "load" task.
          @@ -12335,7 +12335,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def readSchemas(self):
               schemaDir = self.schemaDir
          @@ -12419,7 +12419,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def task(
               self,
          diff --git a/tf/convert/tf.html b/tf/convert/tf.html
          index 2e3036693..eb7406ab2 100644
          --- a/tf/convert/tf.html
          +++ b/tf/convert/tf.html
          @@ -32,7 +32,7 @@ 

          Raw, unoptimised data from TF files<
          Expand source code -Browse git +Browse git
          """
           # Raw, unoptimised data from TF files
          @@ -419,7 +419,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def explode(inPath, outPath):
               """Explodes `.tf` files into non-optimised `.tf` files without metadata.
          diff --git a/tf/convert/variants.html b/tf/convert/variants.html
          index 9f03e288e..459bd65ff 100644
          --- a/tf/convert/variants.html
          +++ b/tf/convert/variants.html
          @@ -38,7 +38,7 @@ 

          Variants

          Expand source code -Browse git +Browse git
          """
           # Variants
          @@ -676,7 +676,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          class Variants:
               def __init__(self, cv, cur, baseWitness, sentType, checkPunc, addWarning, addError):
          @@ -1215,7 +1215,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def checkSent(self, trans, punc):
               """Checks whether there is a "sentence" boundary at this point.
          @@ -1263,7 +1263,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def collectWitnesses(self, node):
               """Collect all witnesses.
          @@ -1333,7 +1333,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def endApp(self, tag):
               """Actions at the end of `app`- `lem`- and `rdg`-elements.
          @@ -1393,7 +1393,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def endSent(self):
               """Ends a "sentence" if there is a current sentence.
          @@ -1432,7 +1432,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def initApps(self):
               """Initialize app- processing and witness collection.
          @@ -1461,7 +1461,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def resetApps(self):
               """Initialize app- and "sentence" processing.
          @@ -1504,7 +1504,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def startApp(self, tag, atts):
               """Actions at the start of `app`- `lem`- and `rdg`-elements.
          @@ -1585,7 +1585,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def startSent(self):
               """Starts a "sentence" if there is no current sentence.
          diff --git a/tf/convert/walker.html b/tf/convert/walker.html
          index f1afe87b6..d8c37cc4b 100644
          --- a/tf/convert/walker.html
          +++ b/tf/convert/walker.html
          @@ -157,7 +157,7 @@ 

          Action methods

          Expand source code -Browse git +Browse git
          """
           # Walker
          @@ -1971,7 +1971,7 @@ 

          Classes

          Expand source code -Browse git +Browse git
          class CV:
               S = "slot"
          @@ -3653,7 +3653,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def active(self, node):
               """Returns whether a node is currently active.
          @@ -3707,7 +3707,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def activeNodes(self, nTypes=None):
               """The currently active nodes, i.e. the embedders.
          @@ -3755,7 +3755,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def activeTypes(self):
               """The node types of the currently active nodes, i.e. the embedders.
          @@ -3799,7 +3799,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def delete(self, node):
               """**deletes** a node.
          @@ -3867,7 +3867,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def edge(self, nodeFrom, nodeTo, **features):
               """Adds **edge features**.
          @@ -3932,7 +3932,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def feature(self, node, **features):
               """Adds **node features**.
          @@ -3982,7 +3982,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def features(self):
               """Gets the list of all features.
          @@ -4030,7 +4030,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def get(self, feature, *args):
               """Retrieves feature values.
          @@ -4102,7 +4102,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def link(self, node, slots):
               """Links the given, existing slots to a node.
          @@ -4166,7 +4166,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def linked(self, node):
               """Returns the slots `ss` to which a node is currently linked.
          @@ -4227,7 +4227,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def meta(self, feat, **metadata):
               """Adds, modifies, deletes metadata fields of features.
          @@ -4330,7 +4330,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def node(self, nType, slots=None):
               """Makes a non-slot node and return the handle to it in `n`.
          @@ -4448,7 +4448,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def occurs(self, feat):
               """Whether the feature `featureName` occurs in the resulting data so far.
          @@ -4512,7 +4512,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def resume(self, node):
               """**resumes** a node.
          @@ -4588,7 +4588,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def slot(self, key=None):
               """Makes a slot node and return the handle to it in `n`.
          @@ -4680,7 +4680,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def stop(self, msg):
               """Stops the director. No further input will be read.
          @@ -4735,7 +4735,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def terminate(self, node):
               """**terminates** a node.
          @@ -4850,7 +4850,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def walk(
               self,
          diff --git a/tf/convert/watm.html b/tf/convert/watm.html
          index c43ab8ac9..4642c317c 100644
          --- a/tf/convert/watm.html
          +++ b/tf/convert/watm.html
          @@ -589,7 +589,7 @@ 

          Caveat

          Expand source code -Browse git +Browse git
          """Export to Web Annotation Text Model
           
          @@ -3106,7 +3106,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def getResultDir(baseDir, headPart, version, prod):
               """Determines the directory for the resulting WATM.
          @@ -3223,7 +3223,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def rep(status):
               """Represent a boolean status for a message to the console.
          @@ -3279,7 +3279,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          class WATM:
               """The export machinery is exposed as a class, wrapped around a TF dataset."""
          @@ -4899,7 +4899,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          @staticmethod
           def numEqual(nTF, nWA, silent):
          @@ -4948,7 +4948,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          @staticmethod
           def strEqual(tf, wa, silent):
          @@ -5020,7 +5020,7 @@ 

          Methods

          Expand source code -Browse git +Browse git
          def makeAnno(self):
               """Make all annotations.
          @@ -5238,7 +5238,7 @@ 

          Methods

          Expand source code -Browse git +Browse git
          def makeText(self):
               """Creates the text data.
          @@ -5328,7 +5328,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def mkAnno(self, kind, ns, body, target):
               """Make a single annotation and return its id.
          @@ -5374,7 +5374,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def testAll(self, condensed=False):
               """Test all aspects of the WATM conversion.
          @@ -5458,7 +5458,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def testAttributes(self):
               """Test the attributes.
          @@ -5691,7 +5691,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def testEdges(self):
               """Test the edges.
          @@ -5892,7 +5892,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def testElements(self):
               """Test the elements.
          @@ -6084,7 +6084,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def testExtra(self):
               """Test the extra data for on-the-fly annotations.
          @@ -6186,7 +6186,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def testSetup(self):
               """Prepare the tests.
          @@ -6359,7 +6359,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def testText(self):
               """Test the text.
          @@ -6438,7 +6438,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def writeAll(self, prod=False, resultVersion=None):
               """Write text and annotation data to disk.
          @@ -6678,7 +6678,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          class WATMS:
               """Export corpora that are divided over multiple TF datasets.
          @@ -6838,7 +6838,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def produce(self, doc=None, prod=False):
               """Convert all relevant TF datasets.
          diff --git a/tf/convert/xml.html b/tf/convert/xml.html
          index aa27377fb..da53b8aeb 100644
          --- a/tf/convert/xml.html
          +++ b/tf/convert/xml.html
          @@ -135,7 +135,7 @@ 

          Examples

          Expand source code -Browse git +Browse git
          """
           # XML import
          @@ -1399,7 +1399,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def main():
               (good, tasks, params, flags) = readArgs(
          @@ -1539,7 +1539,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          class XML(CheckImport):
               def __init__(
          @@ -2613,7 +2613,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def appTask(self, tokenBased=False):
               """Implementation of the "app" task.
          @@ -2862,7 +2862,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def browseTask(self):
               """Implementation of the "browse" task.
          @@ -2928,7 +2928,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def checkTask(self):
               """Implementation of the "check" task.
          @@ -3175,7 +3175,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def convertTask(self):
               """Implementation of the "convert" task.
          @@ -3213,7 +3213,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def getConverter(self):
               """Initializes a converter.
          @@ -3245,7 +3245,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def getParser(self):
               """Configure the LXML parser.
          @@ -3288,7 +3288,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def getXML(self):
               """Make an inventory of the XML source files.
          @@ -3348,7 +3348,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def loadTask(self):
               """Implementation of the "load" task.
          @@ -3432,7 +3432,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def task(
               self,
          diff --git a/tf/convert/xmlCustom.html b/tf/convert/xmlCustom.html
          index c7e5a901e..98a0aab42 100644
          --- a/tf/convert/xmlCustom.html
          +++ b/tf/convert/xmlCustom.html
          @@ -31,7 +31,7 @@ 

          Module tf.convert.xmlCustom

          Expand source code -Browse git +Browse git
          import re
           from io import BytesIO
          @@ -384,7 +384,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def convertTaskDefault(etree):
               if etree is None:
          @@ -482,7 +482,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def getDirector(self, etree):
               """Factory for the director function.
          diff --git a/tf/core/api.html b/tf/core/api.html
          index d6376e557..dcb7a2b0b 100644
          --- a/tf/core/api.html
          +++ b/tf/core/api.html
          @@ -33,7 +33,7 @@ 

          The core API of TF.

          Expand source code -Browse git +Browse git
          """
           # The core API of TF.
          @@ -639,7 +639,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def addLocality(api):
               api.L = Locality(api)
          @@ -654,7 +654,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def addNodes(api):
               api.N = Nodes(api)
          @@ -669,7 +669,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def addOtype(api):
               setattr(api.F.otype, "all", tuple(o[0] for o in api.C.levels.data))
          @@ -686,7 +686,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def addSearch(api, silent=SILENT_D):
               silent = silentConvert(silent)
          @@ -702,7 +702,7 @@ 

          Functions

          Expand source code -Browse git +Browse git
          def addText(api):
               api.T = Text(api)
          @@ -723,7 +723,7 @@ 

          Classes

          Expand source code -Browse git +Browse git
          class Api:
               def __init__(self, TF):
          @@ -1250,7 +1250,7 @@ 

          Methods

          Expand source code -Browse git +Browse git
          def Call(self):
               """Returns a sorted list of all usable, loaded computed data names."""
          @@ -1279,7 +1279,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def Cs(self, fName, warn=True):
               """Get the computed data sub API.
          @@ -1321,7 +1321,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def Eall(self, warp=True):
               """Returns a sorted list of all usable, loaded edge feature names.
          @@ -1356,7 +1356,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def Es(self, fName, warn=True):
               """Get the edge feature sub API.
          @@ -1398,7 +1398,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def Fall(self, warp=True):
               """Returns a sorted list of all usable, loaded node feature names.
          @@ -1433,7 +1433,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def Fs(self, fName, warn=True):
               """Get the node feature sub API.
          @@ -1484,7 +1484,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def ensureLoaded(self, features):
               """Checks if features are loaded and if not loads them.
          @@ -1552,7 +1552,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def footprint(self, recompute=False, bySize=True):
               """Computes the memory footprint in RAM of the loaded TF data.
          @@ -1673,7 +1673,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def isLoaded(
               self, features=None, pretty=True, valueType=True, path=False, meta="description"
          @@ -1951,7 +1951,7 @@ 

          Notes

          Expand source code -Browse git +Browse git
          def makeAvailableIn(self, scope):
               """Exports members of the API to the global namespace.
          diff --git a/tf/core/command.html b/tf/core/command.html
          index 8e2d81c4e..d630e7e9a 100644
          --- a/tf/core/command.html
          +++ b/tf/core/command.html
          @@ -31,7 +31,7 @@ 

          Module tf.core.command

          Expand source code -Browse git +Browse git
          import sys
           from textwrap import dedent
          @@ -250,7 +250,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def readArgs(
               command, descr, possibleTasks, possibleParams, possibleFlags, notInAll=set()
          diff --git a/tf/core/computed.html b/tf/core/computed.html
          index 4fb42307f..3f2403269 100644
          --- a/tf/core/computed.html
          +++ b/tf/core/computed.html
          @@ -52,7 +52,7 @@ 

          Pre-computed data components

          Expand source code -Browse git +Browse git
          """
           # Pre-computed data components
          @@ -117,7 +117,7 @@ 

          Classes

          Expand source code -Browse git +Browse git
          class Computed:
               """Provides access to pre-computed data.
          @@ -138,7 +138,7 @@ 

          Classes

          Expand source code -Browse git +Browse git
          class Computeds:
               pass
          diff --git a/tf/core/data.html b/tf/core/data.html index 8bb7b9877..6184a8d6b 100644 --- a/tf/core/data.html +++ b/tf/core/data.html @@ -31,7 +31,7 @@

          Module tf.core.data

          Expand source code -Browse git +Browse git
          import array
           import gc
          @@ -775,7 +775,7 @@ 

          Classes

          Expand source code -Browse git +Browse git
          class Data:
               def __init__(
          @@ -1466,7 +1466,7 @@ 

          Methods

          Expand source code -Browse git +Browse git
          def cleanDataBin(self):
               fileRemove(self.binPath)
          @@ -1483,7 +1483,7 @@

          Methods

          Expand source code -Browse git +Browse git
          def load(self, metaOnly=False, silent=SILENT_D, _withGc=True):
               """Load a feature.
          @@ -1604,7 +1604,7 @@ 

          Methods

          Expand source code -Browse git +Browse git
          def save(self, overwrite=False, nodeRanges=False, silent=SILENT_D):
               silent = silentConvert(silent)
          @@ -1627,7 +1627,7 @@ 

          Methods

          Expand source code -Browse git +Browse git
          def unload(self):
               self.data = None
          diff --git a/tf/core/edgefeature.html b/tf/core/edgefeature.html
          index 6c39d6c61..705c29645 100644
          --- a/tf/core/edgefeature.html
          +++ b/tf/core/edgefeature.html
          @@ -46,7 +46,7 @@ 

          Module tf.core.edgefeature

          Expand source code -Browse git +Browse git
          """
           Mappings from edges to values.
          @@ -347,7 +347,7 @@ 

          Classes

          Expand source code -Browse git +Browse git
          class EdgeFeature:
               """Provides access to (edge) feature data.
          @@ -672,7 +672,7 @@ 

          Notes

          Expand source code -Browse git +Browse git
          def b(self, n):
               """Query *both* incoming edges to, and outgoing edges from a node.
          @@ -783,7 +783,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def f(self, n):
               """Get outgoing edges *from* a node.
          @@ -848,7 +848,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def freqList(self, nodeTypesFrom=None, nodeTypesTo=None):
               """Frequency list of the values of this feature.
          @@ -925,7 +925,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def items(self):
               """A generator that yields the items of the feature, seen as a mapping.
          @@ -971,7 +971,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def t(self, n):
               """Get incoming edges *to* a node.
          @@ -1018,7 +1018,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          class EdgeFeatures:
               pass
          diff --git a/tf/core/fabric.html b/tf/core/fabric.html index 18a27c6b9..29dadf45e 100644 --- a/tf/core/fabric.html +++ b/tf/core/fabric.html @@ -41,7 +41,7 @@

          Expand source code -Browse git +Browse git
          """
           # `FabricCore`
          @@ -1205,7 +1205,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          class FabricCore:
               """Initialize the core API for a corpus.
          @@ -2189,7 +2189,7 @@ 

          See Also

          Expand source code -Browse git +Browse git
          def clearCache(self):
               """Clears the cache of compiled TF data.
          @@ -2254,7 +2254,7 @@ 

          Notes

          Expand source code -Browse git +Browse git
          def explore(self, silent=SILENT_D, show=True):
               """Makes categorization of all features in the dataset.
          @@ -2363,7 +2363,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def load(self, features, add=False, silent=SILENT_D):
               """Loads features from disk into RAM memory.
          @@ -2541,7 +2541,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def loadAll(self, silent=SILENT_D):
               """Load all loadable features.
          @@ -2642,7 +2642,7 @@ 

          Parameters

          Expand source code -Browse git +Browse git
          def save(
               self,
          diff --git a/tf/core/files.html b/tf/core/files.html
          index 2fd5b1251..1f1450760 100644
          --- a/tf/core/files.html
          +++ b/tf/core/files.html
          @@ -31,7 +31,7 @@ 

          Module tf.core.files

          Expand source code -Browse git +Browse git
          import os
           import yaml
          @@ -313,7 +313,6 @@ 

          Module tf.core.files

          * The input directory is located next to the TF data of the corpus * The output directory is located in the `_temp` directory next to the TF data of the corpus - * The report directory is located in the `report` directory next to the TF data of the corpus Parameters @@ -332,7 +331,7 @@

          Module tf.core.files

          appPath = context.appPath localDir = context.localDir baseDir = dirNm(appPath) - return (f"{baseDir}/{tool}", f"{localDir}/{tool}", f"{baseDir}/report/{tool}") + return (f"{baseDir}/{tool}", f"{localDir}/{tool}") URL_TFDOC = f"https://{ORG}.{backendRep(GH, 'pages')}/{REPO}/tf" @@ -884,7 +883,7 @@

          Functions

          Expand source code -Browse git +Browse git
          def abspath(path):
               return normpath(os.path.abspath(path))
          @@ -898,8 +897,7 @@

          Functions

          • The input directory is located next to the TF data of the corpus
          • The output directory is located in the _temp directory next to the TF data of -the corpus
          • -
          • The report directory is located in the report directory next to the TF data +the corpus of the corpus

          Parameters

          @@ -917,7 +915,7 @@

          Returns

          Expand source code -Browse git +Browse git
          def annotateDir(app, tool):
               """Return the input and output and report directories for a specific annotation tool.
          @@ -925,7 +923,6 @@ 

          Returns

          * The input directory is located next to the TF data of the corpus * The output directory is located in the `_temp` directory next to the TF data of the corpus - * The report directory is located in the `report` directory next to the TF data of the corpus Parameters @@ -944,7 +941,7 @@

          Returns

          appPath = context.appPath localDir = context.localDir baseDir = dirNm(appPath) - return (f"{baseDir}/{tool}", f"{localDir}/{tool}", f"{baseDir}/report/{tool}")
          + return (f"{baseDir}/{tool}", f"{localDir}/{tool}")

      • @@ -1002,7 +999,7 @@

        Returns

        Expand source code -Browse git +Browse git
        def backendRep(be, kind, default=None):
             """Various back-end dependent values.
        @@ -1126,7 +1123,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def chDir(directory):
             """Change to other directory.
        @@ -1154,7 +1151,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def clearTree(path):
             """Remove all files from a directory, recursively, but leave subdirectories.
        @@ -1211,7 +1208,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def dirAllFiles(path, ignore=None):
             """Gets all the files found by `path`.
        @@ -1280,7 +1277,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def dirContents(path):
             """Gets the contents of a directory.
        @@ -1325,7 +1322,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def dirCopy(pathSrc, pathDst, noclobber=False):
             """Copies a directory if it exists as directory.
        @@ -1351,7 +1348,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def dirEmpty(target):
             target = normpath(target)
        @@ -1366,7 +1363,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def dirExists(path):
             """Whether a path exists as directory on the file system."""
        @@ -1389,7 +1386,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def dirMake(path):
             """Creates a directory if it does not already exist as directory."""
        @@ -1406,7 +1403,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def dirMove(pathSrc, pathDst):
             """Moves a directory if it exists as directory.
        @@ -1427,7 +1424,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def dirNm(path):
             """Get the directory part of a file name."""
        @@ -1442,7 +1439,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def dirRemove(path):
             """Removes a directory if it exists as directory."""
        @@ -1458,7 +1455,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def expandDir(obj, dirName):
             if dirName.startswith("~"):
        @@ -1478,7 +1475,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def expanduser(path):
             nPath = normpath(path)
        @@ -1498,7 +1495,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def extNm(path):
             """Get the extension part of a file name.
        @@ -1519,7 +1516,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def fileCopy(pathSrc, pathDst):
             """Copies a file if it exists as file.
        @@ -1539,7 +1536,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def fileExists(path):
             """Whether a path exists as file on the file system."""
        @@ -1555,7 +1552,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def fileMove(pathSrc, pathDst):
             """Moves a file if it exists as file.
        @@ -1575,7 +1572,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def fileNm(path):
             """Get the file part of a file name."""
        @@ -1593,7 +1590,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def fileOpen(*args, **kwargs):
             """Wrapper around `open()`, making sure `encoding="utf8" is passed.
        @@ -1616,7 +1613,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def fileRemove(path):
             """Removes a file if it exists as file."""
        @@ -1637,7 +1634,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def getCwd():
             """Get current directory.
        @@ -1679,7 +1676,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def getLocation(targetDir=None):
             """Get back-end, org, repo, relative of directory.
        @@ -1760,7 +1757,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def initTree(path, fresh=False, gentle=False):
             """Make sure a directory exists, optionally clean it.
        @@ -1802,7 +1799,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def isDir(path):
             """Whether path exists and is a directory."""
        @@ -1817,7 +1814,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def isFile(path):
             """Whether path exists and is a file."""
        @@ -1832,7 +1829,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def normpath(path):
             if path is None:
        @@ -1849,7 +1846,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def prefixSlash(path):
             """Prefix a / before a path if it is non-empty and not already starts with it."""
        @@ -1864,7 +1861,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def readYaml(text=None, plain=False, asFile=None, preferTuples=True):
             kwargs = dict(Loader=yaml.FullLoader)
        @@ -1889,7 +1886,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def replaceExt(path, newExt):
             """Replace the extension of a path by another one. Specify it without dot."""
        @@ -1905,7 +1902,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def setDir(obj):
             obj.homeDir = expanduser("~")
        @@ -1921,7 +1918,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def splitPath(path):
             """Split a file name in a directory part and a file part."""
        @@ -1937,7 +1934,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def str_presenter(dumper, data):
             """configures yaml for dumping multiline strings
        @@ -1957,7 +1954,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def stripExt(path):
             """Strip the extension of a file name, if there is one."""
        @@ -1974,7 +1971,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def unexpanduser(path):
             nPath = normpath(path)
        @@ -1992,7 +1989,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def writeYaml(data, asFile=None, sorted=False):
             kwargs = dict(allow_unicode=True, sort_keys=sorted)
        diff --git a/tf/core/generic.html b/tf/core/generic.html
        index 2dc30ec40..580829051 100644
        --- a/tf/core/generic.html
        +++ b/tf/core/generic.html
        @@ -31,7 +31,7 @@ 

        Module tf.core.generic

        Expand source code -Browse git +Browse git
        class AttrDict(dict):
             """Turn a dict into an object with attributes.
        @@ -190,7 +190,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def deepAttrDict(info, preferTuples=False):
             """Turn a `dict` into an `AttrDict`, recursively.
        @@ -254,7 +254,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def deepdict(info):
             """Turns an `AttrDict` into a `dict`, recursively.
        @@ -304,7 +304,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def isIterable(value):
             """Whether a value is a non-string iterable.
        @@ -346,7 +346,7 @@ 

        Classes

        Expand source code -Browse git +Browse git
        class AttrDict(dict):
             """Turn a dict into an object with attributes.
        @@ -401,7 +401,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def deepdict(self):
             return deepdict(self)
        diff --git a/tf/core/helpers.html b/tf/core/helpers.html index b0ad23342..21fda47c8 100644 --- a/tf/core/helpers.html +++ b/tf/core/helpers.html @@ -31,7 +31,7 @@

        Module tf.core.helpers

        Expand source code -Browse git +Browse git
        import os
         import sys
        @@ -732,7 +732,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def camel(name):
             if not name:
        @@ -749,7 +749,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def check32():
             warn = ""
        @@ -770,7 +770,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def cleanName(name):
             clean = "".join(c if c in VALID else "_" for c in name)
        @@ -787,7 +787,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def collectFormats(config):
             featureSet = set()
        @@ -824,7 +824,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def console(*msg, error=False, newline=True):
             msg = " ".join(m if type(m) is str else repr(m) for m in msg)
        @@ -852,7 +852,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def deepSize(o, handlers={}, verbose=False, seen=None):
             """Returns the approximate memory footprint an object and all of its contents.
        @@ -911,7 +911,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def fitemize(value):
             if not value:
        @@ -931,7 +931,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def flattenToSet(features):
             theseFeatures = set()
        @@ -968,7 +968,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def formatMeta(featureMeta):
             """Reorder meta data.
        @@ -1017,7 +1017,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def getAllRealFeatures(api):
             """Get all configuration features and all loaded node and edge features.
        @@ -1062,7 +1062,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def htmlEsc(val, math=False):
             """Escape certain HTML characters by HTML entities.
        @@ -1102,7 +1102,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def isClean(name):
             if name is None or len(name) == 0 or name[0] not in LETTER:
        @@ -1118,7 +1118,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def isInt(val):
             try:
        @@ -1136,7 +1136,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def itemize(string, sep=None):
             if not string:
        @@ -1154,7 +1154,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def makeExamples(nodeList):
             lN = len(nodeList)
        @@ -1177,7 +1177,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def makeIndex(data):
             inv = {}
        @@ -1194,7 +1194,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def makeInverse(data):
             inverse = {}
        @@ -1212,7 +1212,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def makeInverseVal(data):
             inverse = {}
        @@ -1232,7 +1232,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def mathEsc(val):
             """Escape dollar signs to `<span>$</span>`.
        @@ -1260,7 +1260,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def mdEsc(val, math=False):
             """Escape certain markdown characters.
        @@ -1300,7 +1300,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def mdhtmlEsc(val, math=False):
             """Escape certain Markdown characters by HTML entities or span elements.
        @@ -1354,7 +1354,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def mergeDict(source, overrides):
             """Merge overrides into a source dictionary recursively.
        @@ -1382,7 +1382,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def mergeDictOfSets(d1, d2):
             for n, ms in d2.items():
        @@ -1400,7 +1400,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def nbytes(by):
             units = ["B", "KB", "MB", "GB", "TB"]
        @@ -1421,7 +1421,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def pandasEsc(x):
             """Escapes the character that will be used as the `pandas` quote char.
        @@ -1446,7 +1446,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def project(iterableOfTuples, maxDimension):
             if maxDimension == 1:
        @@ -1462,7 +1462,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def rangesFromList(nodeList):  # the list must be sorted
             curstart = None
        @@ -1489,7 +1489,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def rangesFromSet(nodeSet):
             # ranges = []
        @@ -1531,7 +1531,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def run(cmdline, workDir=None):
             """Runs a shell command and returns all relevant info.
        @@ -1575,7 +1575,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def setFromSpec(spec):
             covered = set()
        @@ -1601,7 +1601,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def setFromStr(x):
             if x is None:
        @@ -1618,7 +1618,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def setFromValue(x, asInt=False):
             if x is None:
        @@ -1643,7 +1643,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def specFromRanges(ranges):  # ranges must be normalized
             return ",".join(
        @@ -1659,7 +1659,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def specFromRangesLogical(ranges):  # ranges must be normalized
             return [r[0] if r[0] == r[1] else [r[0], r[1]] for r in ranges]
        @@ -1673,7 +1673,7 @@

        Parameters

        Expand source code -Browse git +Browse git
        def tfFromValue(val):
             valTp = type(val)
        @@ -1699,7 +1699,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def tsvEsc(x):
             """Escapes a double quote for strings to be included in TSV data.
        @@ -1719,7 +1719,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def valueFromTf(tf):
             return "\\".join(
        @@ -1745,7 +1745,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def var(envVar):
             """Retrieves the value of an environment variable.
        @@ -1771,7 +1771,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def versionSort(x):
             parts = []
        @@ -1792,7 +1792,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def wrapMessages(messages):
             if type(messages) is str:
        @@ -1827,7 +1827,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def xmlEsc(val):
             """Escape certain HTML characters by XML entities.
        diff --git a/tf/core/index.html b/tf/core/index.html
        index 6c5e12b66..41414bcb2 100644
        --- a/tf/core/index.html
        +++ b/tf/core/index.html
        @@ -44,7 +44,7 @@ 

        Core API of TF

        Expand source code -Browse git +Browse git
        """
         # Core API of TF
        diff --git a/tf/core/locality.html b/tf/core/locality.html
        index 8f5f99cd1..ee8bbea0a 100644
        --- a/tf/core/locality.html
        +++ b/tf/core/locality.html
        @@ -32,7 +32,7 @@ 

        Local navigation between nodes.

        Expand source code -Browse git +Browse git
        """
         # Local navigation between nodes.
        @@ -404,7 +404,7 @@ 

        Classes

        Expand source code -Browse git +Browse git
        class Locality:
             """Methods by which you can navigate from a node to its neighbourhood.
        @@ -742,7 +742,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def d(self, n, otype=None):
             """Produces an ordered tuple of *downward* nodes.
        @@ -836,7 +836,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def i(self, n, otype=None):
             """Produces an ordered tuple of *intersecting* nodes
        @@ -918,7 +918,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def n(self, n, otype=None):
             """Produces an ordered tuple of *next* nodes.
        @@ -994,7 +994,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def p(self, n, otype=None):
             """Produces an ordered tuple of *previous* nodes.
        @@ -1075,7 +1075,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def u(self, n, otype=None):
             """Produces an ordered tuple of *upward* nodes.
        diff --git a/tf/core/nodefeature.html b/tf/core/nodefeature.html
        index 2587914be..9fc66bae6 100644
        --- a/tf/core/nodefeature.html
        +++ b/tf/core/nodefeature.html
        @@ -41,7 +41,7 @@ 

        Mappings from nodes to values.

        Expand source code -Browse git +Browse git
        """
         # Mappings from nodes to values.
        @@ -197,7 +197,7 @@ 

        Classes

        Expand source code -Browse git +Browse git
        class NodeFeature:
             """Provides access to (node) feature data.
        @@ -339,7 +339,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def freqList(self, nodeTypes=None):
             """Frequency list of the values of this feature.
        @@ -386,7 +386,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def items(self):
             """A generator that yields the items of the feature, seen as a mapping.
        @@ -427,7 +427,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def s(self, val):
             """Query all nodes having a specified feature value.
        @@ -475,7 +475,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def v(self, n):
             """Get the value of a feature for a node.
        @@ -506,7 +506,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        class NodeFeatures:
             pass
        diff --git a/tf/core/nodes.html b/tf/core/nodes.html index 8d311ab28..aab1d16cb 100644 --- a/tf/core/nodes.html +++ b/tf/core/nodes.html @@ -81,7 +81,7 @@

        Canonical Order

        Expand source code -Browse git +Browse git
        """
         # Node organization
        @@ -399,7 +399,7 @@ 

        Classes

        Expand source code -Browse git +Browse git
        class Nodes:
             def __init__(self, api):
        @@ -710,7 +710,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def makeSortKeyChunk(self):
             api = self.api
        @@ -802,7 +802,7 @@ 

        See Also

        Expand source code -Browse git +Browse git
        def sortNodes(self, nodeSet):
             """Delivers a tuple of nodes sorted by the *canonical ordering*.
        @@ -871,7 +871,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def walk(self, nodes=None, events=False):
             """Generates all nodes in the *canonical order*.
        diff --git a/tf/core/oslotsfeature.html b/tf/core/oslotsfeature.html
        index 2390df301..33dc7c207 100644
        --- a/tf/core/oslotsfeature.html
        +++ b/tf/core/oslotsfeature.html
        @@ -35,7 +35,7 @@ 

        Access to oslots feature dat
        Expand source code -Browse git +Browse git
        """
         # Access to `oslots` feature data.
        @@ -120,7 +120,7 @@ 

        Classes

        Expand source code -Browse git +Browse git
        class OslotsFeature:
             def __init__(self, api, metaData, data):
        @@ -196,7 +196,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def items(self):
             """A generator that yields the non-slot nodes with their slots.
        @@ -235,7 +235,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def s(self, n):
             """Get the slots of a (non-slot) node.
        diff --git a/tf/core/otypefeature.html b/tf/core/otypefeature.html
        index ff1467b46..8a258757c 100644
        --- a/tf/core/otypefeature.html
        +++ b/tf/core/otypefeature.html
        @@ -35,7 +35,7 @@ 

        Access to otype feature data.
        Expand source code -Browse git +Browse git
        """
         # Access to `otype` feature data.
        @@ -190,7 +190,7 @@ 

        Classes

        Expand source code -Browse git +Browse git
        class OtypeFeature:
             def __init__(self, api, metaData, data):
        @@ -351,7 +351,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def items(self):
             """As in `tf.core.nodefeature.NodeFeature.items`."""
        @@ -392,7 +392,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def s(self, val):
             """Query all nodes having a specified node type.
        @@ -452,7 +452,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def sInterval(self, val):
             """The interval of nodes having a specified node type.
        @@ -498,7 +498,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def v(self, n):
             """Get the node type of a node.
        diff --git a/tf/core/prepare.html b/tf/core/prepare.html
        index b09e19d13..1c79e5b4a 100644
        --- a/tf/core/prepare.html
        +++ b/tf/core/prepare.html
        @@ -39,7 +39,7 @@ 

        Pre-compute data.

        Expand source code -Browse git +Browse git
        """
         # Pre-compute data.
        @@ -872,7 +872,7 @@ 

        Notes

        Expand source code -Browse git +Browse git
        def boundary(info, error, otype, oslots, rank):
             """Computes boundary data.
        @@ -971,7 +971,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def characters(info, error, otext, tFormats, *tFeats):
             """Computes character data.
        @@ -1071,7 +1071,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def levDown(info, error, otype, levUp, rank):
             """Computes level-down data.
        @@ -1170,7 +1170,7 @@ 

        Warnings

        Expand source code -Browse git +Browse git
        def levUp(info, error, otype, oslots, rank):
             """Computes level-up data.
        @@ -1320,7 +1320,7 @@ 

        Notes

        Expand source code -Browse git +Browse git
        def levels(info, error, otype, oslots, otext):
             """Computes level data.
        @@ -1472,7 +1472,7 @@ 

        See Also

        Expand source code -Browse git +Browse git
        def order(info, error, otype, oslots, levels):
             """Computes order data for the canonical ordering.
        @@ -1577,7 +1577,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def rank(info, error, otype, order):
             """Computes rank data.
        @@ -1664,7 +1664,7 @@ 

        Warnings

        Expand source code -Browse git +Browse git
        def sections(info, error, otype, oslots, otext, levUp, levels, *sFeats):
             """Computes section data.
        @@ -1852,7 +1852,7 @@ 

        Notes

        Expand source code -Browse git +Browse git
        def structure(info, error, otype, oslots, otext, rank, levUp, *sFeats):
             """Computes structure data.
        diff --git a/tf/core/text.html b/tf/core/text.html
        index 64d8437aa..db07e00a0 100644
        --- a/tf/core/text.html
        +++ b/tf/core/text.html
        @@ -374,7 +374,7 @@ 

        The T.text() function

        Expand source code -Browse git +Browse git
        """
         # Text API
        @@ -1683,7 +1683,7 @@ 

        Classes

        Expand source code -Browse git +Browse git
        class Text:
             """Low level text representation, including section headings.
        @@ -2632,7 +2632,7 @@ 

        Notes

        Expand source code -Browse git +Browse git
        def down(self, n):
             """Gives the children of a structural node.
        @@ -2704,7 +2704,7 @@ 

        Notes

        Expand source code -Browse git +Browse git
        def headingFromNode(self, n):
             """Gives the full heading of a structural node.
        @@ -2776,7 +2776,7 @@ 

        Notes

        Expand source code -Browse git +Browse git
        def nodeFromHeading(self, head):
             """Gives the node corresponding to a heading, provided it exists.
        @@ -2841,7 +2841,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def nodeFromSection(self, section, lang="en"):
             """Given a section tuple, return the node of it.
        @@ -2925,7 +2925,7 @@ 

        Warnings

        Expand source code -Browse git +Browse git
        def sectionFromNode(self, n, lastSlot=False, lang="en", fillup=False):
             """Gives the full heading of a section node.
        @@ -3024,7 +3024,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def sectionTuple(self, n, lastSlot=False, fillup=False):
             """Gives a tuple of nodes that correspond to a section.
        @@ -3129,7 +3129,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def splitDefaultFormat(self, tpl):
             api = self.api
        @@ -3152,7 +3152,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def splitFormat(self, tpl):
             api = self.api
        @@ -3186,7 +3186,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def structure(self, node=None):
             """Gives the structure of node and everything below it as a tuple.
        @@ -3239,7 +3239,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
            def structureInfo(self):
                 """Gives a summary of how structure has been configured in the dataset.
        @@ -3334,7 +3334,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def structurePretty(self, node=None, fullHeading=False):
             """Gives the structure of node and everything below it as a string.
        @@ -3435,7 +3435,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
            def text(self, nodes, fmt=None, descend=None, func=None, explain=False, **kwargs):
                 """Gives the text that corresponds to a bunch of nodes.
        @@ -3660,7 +3660,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def top(self):
             """Gives all top-level structural nodes in the dataset.
        @@ -3704,7 +3704,7 @@ 

        Notes

        Expand source code -Browse git +Browse git
        def up(self, n):
             """Gives the parent of a structural node.
        diff --git a/tf/core/timestamp.html b/tf/core/timestamp.html
        index c36c86073..71ae413ab 100644
        --- a/tf/core/timestamp.html
        +++ b/tf/core/timestamp.html
        @@ -34,7 +34,7 @@ 

        Timed messages

        Expand source code -Browse git +Browse git
        """
         # Timed messages
        @@ -414,7 +414,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def silentConvert(arg):
             if arg is None:
        @@ -476,7 +476,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        class Timestamp:
             def __init__(self, silent=SILENT_D, level=None):
        @@ -778,7 +778,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def cache(self, _asString=False):
             if _asString:
        @@ -824,7 +824,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def debug(self, msg, tm=True, nl=True, cache=0, force=False):
             """Sends a debug message to the standard output.
        @@ -879,7 +879,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def error(self, msg, tm=True, nl=True, cache=0, force=True):
             """Sends an warning message to the standard error.
        @@ -928,7 +928,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def indent(self, level=None, reset=False, _verbose=None):
             """Changes the indentation and timing of forthcoming messages.
        @@ -996,7 +996,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def info(self, msg, tm=True, nl=True, cache=0, force=False):
             """Sends an informational message to the standard output.
        @@ -1038,7 +1038,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def isSilent(self):
             """The current verbosity.
        @@ -1059,7 +1059,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def raw_msg(self, msg, tm=True, nl=True, cache=0, error=False):
             # cache is a list: append to cache, do not output anything
        @@ -1096,7 +1096,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def reset(self):
             self.log = []
        @@ -1115,7 +1115,7 @@

        Parameters

        Expand source code -Browse git +Browse git
        def setSilent(self, silent):
             """Set the verbosity.
        @@ -1138,7 +1138,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def silentOff(self):
             """Enable informational messages."""
        @@ -1160,7 +1160,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def silentOn(self, deep=False):
             """Suppress informational messages.
        @@ -1203,7 +1203,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def warning(self, msg, tm=True, nl=True, cache=0, force=False):
             """Sends an warning message to the standard output.
        diff --git a/tf/dataset/index.html b/tf/dataset/index.html
        index 6d694f297..3e54402c7 100644
        --- a/tf/dataset/index.html
        +++ b/tf/dataset/index.html
        @@ -43,7 +43,7 @@ 

        Dataset operations

        Expand source code -Browse git +Browse git
        """
         # Dataset operations
        diff --git a/tf/dataset/modify.html b/tf/dataset/modify.html
        index f284d83b3..fc96d98d1 100644
        --- a/tf/dataset/modify.html
        +++ b/tf/dataset/modify.html
        @@ -48,7 +48,7 @@ 

        Usage

        Expand source code -Browse git +Browse git
        """
         # Modify
        @@ -1881,7 +1881,7 @@ 

        Example

        Expand source code -Browse git +Browse git
        def modify(
             location,
        diff --git a/tf/dataset/nodemaps.html b/tf/dataset/nodemaps.html
        index d220b4c2e..54c92d758 100644
        --- a/tf/dataset/nodemaps.html
        +++ b/tf/dataset/nodemaps.html
        @@ -138,7 +138,7 @@ 

        Usage

        Expand source code -Browse git +Browse git
        """
         # Node maps
        @@ -893,7 +893,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        class Versions:
             def __init__(self, api, va, vb, silent=SILENT_D, slotMap=None):
        @@ -1459,7 +1459,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
            def caption(self, level, heading, good=None, newLine=True, continuation=False):
                 silent = self.silent
        @@ -1535,7 +1535,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def exploreNodeMapping(self, nodeType):
             va = self.va
        @@ -1604,7 +1604,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def getDiagnosis(self, node=None, label=None):
             """Show the diagnosis of a mapping.
        @@ -1684,7 +1684,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def legend(self):
             """Show the labels and descriptions of the diagnosis classes.
        @@ -1708,7 +1708,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def makeNodeMapping(self, nodeType):
             edge = self.edge
        @@ -1799,7 +1799,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def makeVersionMapping(self):
             Fa = self.Fa
        @@ -1855,7 +1855,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def migrateFeatures(self, featureNames, silent=None, location=None):
             """Migrate features from one version to another based on a node map.
        @@ -2050,7 +2050,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def omapName(self):
             va = self.va
        @@ -2066,7 +2066,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def writeMap(self):
             TFb = self.TFb
        diff --git a/tf/fabric.html b/tf/fabric.html
        index 5b4c88b43..6f17185ff 100644
        --- a/tf/fabric.html
        +++ b/tf/fabric.html
        @@ -52,7 +52,7 @@ 

        Fabri
        Expand source code -Browse git +Browse git
        """
         # `Fabric`
        @@ -346,7 +346,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        class Fabric(FabricCore):
             """Initialize the core API for a corpus.
        @@ -572,7 +572,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def collect(
             self,
        @@ -628,7 +628,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def extract(
             self, volumes=True, byTitle=True, silent=SILENT_D, overwrite=None, show=False
        @@ -675,7 +675,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def getVolumes(self):
             """Lists available volumes within the dataset.
        diff --git a/tf/images/.DS_Store b/tf/images/.DS_Store
        index 071a6e6e7..3b70b7c3d 100644
        Binary files a/tf/images/.DS_Store and b/tf/images/.DS_Store differ
        diff --git a/tf/index.html b/tf/index.html
        index 6fe710c08..774895d55 100644
        --- a/tf/index.html
        +++ b/tf/index.html
        @@ -154,7 +154,7 @@ 

        More resources

        Expand source code -Browse git +Browse git
        """
         .. include:: docs/main/top.md
        diff --git a/tf/lib.html b/tf/lib.html
        index 274b563e6..3f0e87a25 100644
        --- a/tf/lib.html
        +++ b/tf/lib.html
        @@ -33,7 +33,7 @@ 

        Utility functions

        Expand source code -Browse git +Browse git
        """
         # Utility functions
        @@ -237,7 +237,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def readList(source):
             """Reads list of tuples from a TSV file.
        @@ -300,7 +300,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def readSets(source):
             """Reads a dictionary of named sets from file.
        @@ -370,7 +370,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def writeList(data, dest, intCols=None):
             """Writes a list of tuples sets to a TSV file.
        @@ -457,7 +457,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def writeSets(sets, dest):
             """Writes a dictionary of named sets to file.
        diff --git a/tf/parameters.html b/tf/parameters.html
        index c6f599bda..51171be1e 100644
        --- a/tf/parameters.html
        +++ b/tf/parameters.html
        @@ -33,7 +33,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        """
         # Parameters
        @@ -46,7 +46,7 @@ 

        Parameters

        from zipfile import ZIP_DEFLATED -VERSION = '12.5.1' +VERSION = '12.5.2' """Program version. This value is under control of the update process, as run by diff --git a/tf/search/graph.html b/tf/search/graph.html index 64c5c6344..bbae40fa3 100644 --- a/tf/search/graph.html +++ b/tf/search/graph.html @@ -32,7 +32,7 @@

        Graph oriented functions nee
        Expand source code -Browse git +Browse git
        """
         # Graph oriented functions needed for search
        @@ -290,7 +290,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def connectedness(searchExe):
             error = searchExe.api.TF.error
        @@ -342,7 +342,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def displayEdge(searchExe, e, dir, nodesSeen):
             info = searchExe.api.TF.info
        @@ -396,7 +396,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def displayNode(searchExe, q, pos2=False):
             info = searchExe.api.TF.info
        @@ -424,7 +424,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def displayPlan(searchExe, details=False):
             if not searchExe.good:
        @@ -497,7 +497,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def multiEdges(searchExe):
             relations = searchExe.relations
        diff --git a/tf/search/index.html b/tf/search/index.html
        index ece5a2a01..4ae75342e 100644
        --- a/tf/search/index.html
        +++ b/tf/search/index.html
        @@ -37,7 +37,7 @@ 

        Guidance for searching

        Expand source code -Browse git +Browse git
        """
         # Guidance for searching
        diff --git a/tf/search/relations.html b/tf/search/relations.html
        index 2b2c86a12..f29660a10 100644
        --- a/tf/search/relations.html
        +++ b/tf/search/relations.html
        @@ -32,7 +32,7 @@ 

        Search by relational patter
        Expand source code -Browse git +Browse git
        """
         # Search by relational patterns between nodes
        @@ -1865,7 +1865,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def add_F_Relations(searchExe, varRels):
             relations = searchExe.relations
        @@ -1946,7 +1946,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def add_K_Relations(searchExe, varRels):
             relations = searchExe.relations
        @@ -1999,7 +1999,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def add_V_Relations(searchExe, varRels):
             relations = searchExe.relations
        @@ -2064,7 +2064,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def basicRelations(searchExe, api):
             C = api.C
        diff --git a/tf/search/search.html b/tf/search/search.html
        index 9219ea395..bd247123e 100644
        --- a/tf/search/search.html
        +++ b/tf/search/search.html
        @@ -32,7 +32,7 @@ 

        Search (top-level)

        Expand source code -Browse git +Browse git
        """
         # Search (top-level)
        @@ -596,7 +596,7 @@ 

        Classes

        Expand source code -Browse git +Browse git
        class Search:
             """ """
        @@ -1176,7 +1176,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def count(self, progress=None, limit=None):
             """Counts the results, with progress messages, optionally up to a limit.
        @@ -1278,7 +1278,7 @@ 

        Notes

        Expand source code -Browse git +Browse git
        def fetch(self, limit=None, _msgCache=False):
             """Retrieves query results, up to a limit.
        @@ -1390,7 +1390,7 @@ 

        Notes

        Expand source code -Browse git +Browse git
        def glean(self, tup):
             """Renders a single result into something human readable.
        @@ -1476,7 +1476,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def relationsLegend(self):
             """Dynamic info about the basic relations that can be used in templates.
        @@ -1547,7 +1547,7 @@ 

        Notes

        Expand source code -Browse git +Browse git
        def search(
             self,
        @@ -1657,7 +1657,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def showPlan(self, details=False):
             """Show the result of the latest study of a template.
        @@ -1734,7 +1734,7 @@ 

        See Also

        Expand source code -Browse git +Browse git
        def study(
             self,
        @@ -1917,7 +1917,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def tweakPerformance(self, silent=SILENT_D, **kwargs):
             """Tweak parameters that influence the search process.
        diff --git a/tf/search/searchexe.html b/tf/search/searchexe.html
        index 489b0d3a4..ba5ed2501 100644
        --- a/tf/search/searchexe.html
        +++ b/tf/search/searchexe.html
        @@ -32,7 +32,7 @@ 

        Search execution management

        Expand source code -Browse git +Browse git
        """
         # Search execution management
        @@ -300,7 +300,7 @@ 

        Classes

        Expand source code -Browse git +Browse git
        class SearchExe:
             perfDefaults = dict(
        @@ -553,7 +553,7 @@ 

        Static methods

        Expand source code -Browse git +Browse git
        @classmethod
         def setPerfParams(cls, params):
        @@ -571,7 +571,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def count(self, progress=None, limit=None):
             TF = self.api.TF
        @@ -637,7 +637,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def fetch(self, limit=None):
             api = self.api
        @@ -683,7 +683,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def search(self, limit=None):
             api = self.api
        @@ -703,7 +703,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def showOuterTemplate(self, _msgCache):
             error = self.api.TF.error
        @@ -724,7 +724,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def showPlan(self, details=False):
             displayPlan(self, details=details)
        @@ -738,7 +738,7 @@

        Methods

        Expand source code -Browse git +Browse git
        def study(self, strategy=None):
             api = self.api
        diff --git a/tf/search/semantics.html b/tf/search/semantics.html
        index fd0e4f1a2..de902ef46 100644
        --- a/tf/search/semantics.html
        +++ b/tf/search/semantics.html
        @@ -32,7 +32,7 @@ 

        Semantics of search templates

        Expand source code -Browse git +Browse git
        """
         # Semantics of search templates
        @@ -566,7 +566,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def semantics(searchExe):
             if not searchExe.good:
        diff --git a/tf/search/spin.html b/tf/search/spin.html
        index 3ce5016ee..29d5ed9ce 100644
        --- a/tf/search/spin.html
        +++ b/tf/search/spin.html
        @@ -32,7 +32,7 @@ 

        Search pre-processing

        Expand source code -Browse git +Browse git
        """
         # Search pre-processing
        @@ -484,7 +484,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def estimateSpreads(searchExe, both=False):
             TRY_LIMIT_F = searchExe.perfParams["tryLimitFrom"]
        @@ -562,7 +562,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def spinAtoms(searchExe):
             qnodes = searchExe.qnodes
        @@ -578,7 +578,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def spinEdges(searchExe):
             qnodes = searchExe.qnodes
        diff --git a/tf/search/stitch.html b/tf/search/stitch.html
        index 0af5c0321..5e1449f92 100644
        --- a/tf/search/stitch.html
        +++ b/tf/search/stitch.html
        @@ -32,7 +32,7 @@ 

        Search result finding

        Expand source code -Browse git +Browse git
        """
         # Search result finding
        @@ -937,7 +937,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def setStrategy(searchExe, strategy, keep=False):
             error = searchExe.api.TF.error
        @@ -971,7 +971,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def stitch(searchExe):
             estimateSpreads(searchExe, both=True)
        diff --git a/tf/search/syntax.html b/tf/search/syntax.html
        index 8737dfc77..91a83fb08 100644
        --- a/tf/search/syntax.html
        +++ b/tf/search/syntax.html
        @@ -32,7 +32,7 @@ 

        Syntax of search templates

        Expand source code -Browse git +Browse git
        """
         # Syntax of search templates
        @@ -730,7 +730,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def cleanParent(atom, parentName):
             (kind, data) = parseLine(atom)
        @@ -748,7 +748,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def deContext(quantifier, parentName):
             (quKind, quTemplates, ln) = quantifier
        @@ -804,7 +804,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def parseFeatureVals(searchExe, featStr, features, i, asEdge=False):
             if asEdge:
        @@ -879,7 +879,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def parseLine(line):
             for x in [True]:
        @@ -936,7 +936,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def syntax(searchExe):
             error = searchExe.api.TF.error
        diff --git a/tf/tools/checkdiffs.html b/tf/tools/checkdiffs.html
        index ae777504e..58811ec20 100644
        --- a/tf/tools/checkdiffs.html
        +++ b/tf/tools/checkdiffs.html
        @@ -31,7 +31,7 @@ 

        Module tf.tools.checkdiffs

        Expand source code -Browse git +Browse git
        import sys
         from itertools import zip_longest
        @@ -130,7 +130,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def checkDiffs(path1, path2):
             """Check differences between runs of TF generations.
        diff --git a/tf/tools/index.html b/tf/tools/index.html
        index 65b9c151f..e0ae39838 100644
        --- a/tf/tools/index.html
        +++ b/tf/tools/index.html
        @@ -32,7 +32,7 @@ 

        Module tf.tools

        Expand source code -Browse git +Browse git
        """Various tools for workflows around TF."""
        diff --git a/tf/tools/myspacy.html b/tf/tools/myspacy.html index fc485739e..4a01a2d96 100644 --- a/tf/tools/myspacy.html +++ b/tf/tools/myspacy.html @@ -41,7 +41,7 @@

        Module tf.tools.myspacy

        Expand source code -Browse git +Browse git
        """Get words and tokens from a plain text with the help of Spacy.
         
        @@ -484,7 +484,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def nlpOutput(text, lang="en", ner=False, parser=False):
             """Runs the Spacy NLP pipeline and delivers the results.
        @@ -554,7 +554,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        class Spacy(CheckImport):
             def __init__(self, lang=None, parser=False):
        @@ -885,7 +885,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def getEntities(self):
             """Get the resulting named entities.
        @@ -949,7 +949,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def getSentences(self):
             """Get the resulting sentences.
        @@ -1032,7 +1032,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def getTokens(self):
             """Get the resulting tokens.
        @@ -1099,7 +1099,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def read(self, text):
             """Process a plain text.
        diff --git a/tf/tools/nbconvert.html b/tf/tools/nbconvert.html
        index fa031f889..7129babc8 100644
        --- a/tf/tools/nbconvert.html
        +++ b/tf/tools/nbconvert.html
        @@ -31,7 +31,7 @@ 

        Module tf.tools.nbconvert

        Expand source code -Browse git +Browse git
        import sys
         import re
        @@ -310,7 +310,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def convertDir(inputDir, outputDir):
             inPlace = outputDir == "-"
        @@ -409,7 +409,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def main():
             args = sys.argv[1:]
        @@ -428,7 +428,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def makeIndex(inputDir):
             htmlStart = dedent(
        @@ -536,7 +536,7 @@ 

        Index Mode

        Expand source code -Browse git +Browse git
        def task(*args):
             inputDir = args[0]
        diff --git a/tf/tools/pdocs.html b/tf/tools/pdocs.html
        index 17d53c0a7..8f5a48f9c 100644
        --- a/tf/tools/pdocs.html
        +++ b/tf/tools/pdocs.html
        @@ -31,7 +31,7 @@ 

        Module tf.tools.pdocs

        Expand source code -Browse git +Browse git
        import sys
         import os
        @@ -277,7 +277,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def console(*args):
             sys.stderr.write(" ".join(args) + "\n")
        @@ -292,7 +292,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def getCommand(pkg, asString=False):
             templateLoc = TEMPLATE_LOC.format(pkg)
        @@ -317,7 +317,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def pdoc3(pkg):
             """Build the docs into site."""
        @@ -346,7 +346,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def pdoc3serve(pkg):
             """Build the docs into site and serve them."""
        @@ -369,7 +369,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def servePdocs(pkg):
             run("python -m http.server 9000", cwd=SITE, shell=True)
        @@ -383,7 +383,7 @@

        Functions

        Expand source code -Browse git +Browse git
        def shipDocs(org, repo, pkg, pdoc=True):
             """Build the docs into site and ship them."""
        diff --git a/tf/tools/release.html b/tf/tools/release.html
        index 50456ecfe..85989d126 100644
        --- a/tf/tools/release.html
        +++ b/tf/tools/release.html
        @@ -31,7 +31,7 @@ 

        Module tf.tools.release

        Expand source code -Browse git +Browse git
        import sys
         
        @@ -110,7 +110,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def makeRelease(org, repo, tag, name, msg, silent=True):
             ghPerson = var("GHPERS")
        diff --git a/tf/tools/xmlschema.html b/tf/tools/xmlschema.html
        index 6a260ed6e..79ad971be 100644
        --- a/tf/tools/xmlschema.html
        +++ b/tf/tools/xmlschema.html
        @@ -107,7 +107,7 @@ 

        As library

        Expand source code -Browse git +Browse git
        """
         ## Meaningful information from XML schemas.
        @@ -1180,7 +1180,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def main():
             A = Analysis()
        @@ -1209,7 +1209,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        class Analysis(CheckImport):
             @staticmethod
        @@ -1655,7 +1655,7 @@ 

        Static methods

        Expand source code -Browse git +Browse git
        @staticmethod
         def help():
        @@ -1696,7 +1696,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def analyser(self, baseSchema, override):
             """Initializes an analyser for a schema.
        @@ -1755,7 +1755,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def elements(self, baseSchema, override):
             """Makes a list of elements and their properties.
        @@ -1821,7 +1821,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def fromrelax(self, baseSchema, schemaOut):
             """Converts a RelaxNG schema to an XSD schema.
        @@ -1868,7 +1868,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def getBaseSchema(self):
             """Get the base schema.
        @@ -1910,7 +1910,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def getElementInfo(self, baseSchema, overrides, verbose=None):
             """Analyse the schema and its overrides.
        @@ -1970,7 +1970,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def getModel(self, xmlContent):
             modelRe = self.modelRe
        @@ -2007,7 +2007,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def run(self):
             """Run a task specified by arguments on the command-line.
        @@ -2084,7 +2084,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def setModes(self, debug=False, verbose=-1):
             """Sets debug and verbose modes.
        @@ -2117,7 +2117,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def task(self, task, *args, verbose=None):
             """Implements a higher level task.
        @@ -2207,7 +2207,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def validate(self, schema, instances):
             """Validates an instance against a schema.
        @@ -2295,7 +2295,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        class Elements(CheckImport):
             types = set(
        @@ -2832,7 +2832,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        @staticmethod
         def eKey(x):
        @@ -2869,7 +2869,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        @staticmethod
         def repKind(k):
        @@ -2884,7 +2884,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        @staticmethod
         def repMixed(m):
        @@ -2914,7 +2914,7 @@ 

        Parameters

        Expand source code -Browse git +Browse git
        def configure(self, baseSchema, override=None, roots=None):
             """Configure for an XML schema and overrides
        @@ -3059,7 +3059,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def getDefs(self, asTsv=False):
             """Delivers the analysis results.
        @@ -3118,7 +3118,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def interpret(self):
             """Reads the XSD and interprets the element definitions.
        @@ -3290,7 +3290,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def resolve(self, definitions):
             """Resolve indirections in the definitions.
        @@ -3359,7 +3359,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def showElems(self):
             """Shows the current state of definitions.
        @@ -3396,7 +3396,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def showOverrides(self):
             """Shows the overriding definitions."""
        @@ -3429,7 +3429,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def writeDefs(self, outputDir):
             """Writes the definitions of the elements to a file.
        diff --git a/tf/volumes/collect.html b/tf/volumes/collect.html
        index 64f8c824d..029d7bf93 100644
        --- a/tf/volumes/collect.html
        +++ b/tf/volumes/collect.html
        @@ -54,7 +54,7 @@ 

        Usage

        Expand source code -Browse git +Browse git
        """
         # Collect
        @@ -1187,7 +1187,7 @@ 

        Example

        Expand source code -Browse git +Browse git
        def collect(
             volumes,
        diff --git a/tf/volumes/extract.html b/tf/volumes/extract.html
        index 4bf26ac16..61f8304ab 100644
        --- a/tf/volumes/extract.html
        +++ b/tf/volumes/extract.html
        @@ -40,7 +40,7 @@ 

        Usage

        Expand source code -Browse git +Browse git
        """
         # Extract
        @@ -949,7 +949,7 @@ 

        Example

        Expand source code -Browse git +Browse git
        def extract(
             workLocation,
        @@ -1625,7 +1625,7 @@ 

        Returns

        Expand source code -Browse git +Browse git
        def getVolumes(volumesLocation):
             """Lists volumes of a work that exist in a given directory.
        diff --git a/tf/volumes/index.html b/tf/volumes/index.html
        index a70feda1f..fd41d0021 100644
        --- a/tf/volumes/index.html
        +++ b/tf/volumes/index.html
        @@ -38,7 +38,7 @@ 

        Volume operations

        Expand source code -Browse git +Browse git
        """
         # Volume operations
        diff --git a/tf/writing/arabic.html b/tf/writing/arabic.html
        index 2d08c7ed0..b9bd12e5d 100644
        --- a/tf/writing/arabic.html
        +++ b/tf/writing/arabic.html
        @@ -1019,7 +1019,7 @@ 

        See also

        Expand source code -Browse git +Browse git
        """
         .. include:: ../docs/writing/arabic.md
        diff --git a/tf/writing/greek.html b/tf/writing/greek.html
        index 0f33b638a..35aa3dac5 100644
        --- a/tf/writing/greek.html
        +++ b/tf/writing/greek.html
        @@ -33,7 +33,7 @@ 

        Greek characters

        Expand source code -Browse git +Browse git
        """
         .. include:: ../docs/writing/greek.md
        diff --git a/tf/writing/hebrew.html b/tf/writing/hebrew.html
        index 3ec7596af..1cec77dd3 100644
        --- a/tf/writing/hebrew.html
        +++ b/tf/writing/hebrew.html
        @@ -1243,7 +1243,7 @@ 

        Text-critical

        Expand source code -Browse git +Browse git
        """
         .. include:: ../docs/writing/hebrew.md
        diff --git a/tf/writing/index.html b/tf/writing/index.html
        index 52f862ec6..009821a78 100644
        --- a/tf/writing/index.html
        +++ b/tf/writing/index.html
        @@ -79,7 +79,7 @@ 

        Writing systems support

        Expand source code -Browse git +Browse git
        """
         # Writing systems support
        diff --git a/tf/writing/neoaramaic.html b/tf/writing/neoaramaic.html
        index 71dbe1c89..d214e369c 100644
        --- a/tf/writing/neoaramaic.html
        +++ b/tf/writing/neoaramaic.html
        @@ -148,7 +148,7 @@ 

        Consonant phonem
        Expand source code -Browse git +Browse git
        """
         .. include:: ../docs/writing/neoaramaic.md
        diff --git a/tf/writing/syriac.html b/tf/writing/syriac.html
        index 808fc40f1..f5ebc1408 100644
        --- a/tf/writing/syriac.html
        +++ b/tf/writing/syriac.html
        @@ -609,7 +609,7 @@ 

        Pericope markers

        Expand source code -Browse git +Browse git
        """
         .. include:: ../docs/writing/syriac.md
        diff --git a/tf/writing/transcription.html b/tf/writing/transcription.html
        index 2069ebe50..71a2c5d60 100644
        --- a/tf/writing/transcription.html
        +++ b/tf/writing/transcription.html
        @@ -56,7 +56,7 @@ 

        cld Neo Aramaic

        Expand source code -Browse git +Browse git
        """
         # Transcription
        @@ -1264,7 +1264,7 @@ 

        Classes

        Expand source code -Browse git +Browse git
        class Transcription:
             """Conversion between UNICODE and various transcriptions.
        @@ -2572,7 +2572,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def asciiFromArabic(word):
             return "".join(Transcription.arabicTransAscii.get(x, x) for x in word)
        @@ -2586,7 +2586,7 @@

        Methods

        Expand source code -Browse git +Browse git
        def can_from_syriac(self, word):
             return all(c in self.syriac_mappingi for c in word if c != " ")
        @@ -2600,7 +2600,7 @@

        Methods

        Expand source code -Browse git +Browse git
        def can_to_syriac(self, word):
             return all(
        @@ -2625,7 +2625,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def from_arabic(word):
             """
        @@ -2663,7 +2663,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def from_hebrew(self, word):
             """
        @@ -2703,7 +2703,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def from_syriac(self, word):
             """
        @@ -2741,7 +2741,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def from_ugaritic(word):
             """
        @@ -2772,7 +2772,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def latinFromArabic(word):
             return "".join(Transcription.arabicTransLatin.get(x, x) for x in word)
        @@ -2799,7 +2799,7 @@

        Methods

        Expand source code -Browse git +Browse git
        def ph_simplify(pword):
             """
        @@ -2837,7 +2837,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def quranFromArabic(word):
             return "".join(Transcription.arabicTransQuran.get(x, x) for x in word)
        @@ -2851,7 +2851,7 @@

        Methods

        Expand source code -Browse git +Browse git
        def standardFromArabic(word):
             return "".join(Transcription.arabicTransStandard.get(x, x) for x in word)
        @@ -2884,7 +2884,7 @@

        Methods

        Expand source code -Browse git +Browse git
        def suffix_and_finales(word):
             """
        @@ -2970,7 +2970,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def suppress_space(word):
             """
        @@ -3006,7 +3006,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def sycSplitPunc(self):
             pass
        @@ -3027,7 +3027,7 @@

        Methods

        Expand source code -Browse git +Browse git
        def to_arabic(word):
             """
        @@ -3067,7 +3067,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def to_etcbc_c(word):
             """
        @@ -3116,7 +3116,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def to_etcbc_v(word):
             """
        @@ -3156,7 +3156,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def to_hebrew(word):
             """
        @@ -3198,7 +3198,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def to_hebrew_c(word):
             """
        @@ -3240,7 +3240,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def to_hebrew_v(word):
             """
        @@ -3282,7 +3282,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def to_hebrew_x(word):
             """
        @@ -3322,7 +3322,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def to_syriac(self, word):
             """
        @@ -3362,7 +3362,7 @@ 

        Methods

        Expand source code -Browse git +Browse git
        def to_ugaritic(word):
             """
        diff --git a/tf/writing/ugaritic.html b/tf/writing/ugaritic.html
        index 2f4eec80e..d16bd8d35 100644
        --- a/tf/writing/ugaritic.html
        +++ b/tf/writing/ugaritic.html
        @@ -352,7 +352,7 @@ 

        Letters and word separator

        Expand source code -Browse git +Browse git
        """
         .. include:: ../docs/writing/ugaritic.md
        diff --git a/tf/zip.html b/tf/zip.html
        index fd81efd92..3cb854233 100644
        --- a/tf/zip.html
        +++ b/tf/zip.html
        @@ -31,7 +31,7 @@ 

        Module tf.zip

        Expand source code -Browse git +Browse git
        from .advanced.app import loadApp
         from .core.timestamp import DEEP
        @@ -85,7 +85,7 @@ 

        Functions

        Expand source code -Browse git +Browse git
        def main():
             """Makes a complete zip file.