From 8acdac67da2d1aaf48acf6b996dd4eb8e0f46b5f Mon Sep 17 00:00:00 2001 From: Fabian Gallenkamp <fabian.gallenkamp@uni-hamburg.de> Date: Thu, 21 Feb 2019 12:17:06 +0100 Subject: [PATCH] Fixed small issues --- app.py | 244 ++++++++++++------------------ sample_db.sqlite | Bin 65536 -> 69632 bytes templates/export/softwares.jinja2 | 6 + 3 files changed, 99 insertions(+), 151 deletions(-) diff --git a/app.py b/app.py index 0937225..2936940 100644 --- a/app.py +++ b/app.py @@ -189,7 +189,7 @@ class AdvancedSoftwareView(sqla.ModelView): # Generate overview page with open('templates/export/softwares.jinja2', "r", encoding="utf-8") as file_: template = Template(file_.read()) - template.stream(softwareincategory=softwareincategory).dump('../digitale-Methoden-wiki/Softwareliste.asciidoc', encoding='utf-8') + template.stream(softwareincategory=softwareincategory).dump('../digitale-Methoden-wiki/SoftwareToolsList.asciidoc', encoding='utf-8') base_path = pathlib.Path('../digitale-Methoden-wiki/') data = io.BytesIO() @@ -203,139 +203,25 @@ class AdvancedSoftwareView(sqla.ModelView): as_attachment=True, attachment_filename='data.zip' ) - flash("Done") + flash("Files generated!") except Exception as ex: if not self.handle_view_exception(ex): raise - flash("Not done") -''' -class UserAdmin(sqla.ModelView): - action_disallowed_list = ['delete', ] - column_display_pk = True - column_list = [ - 'id', - 'last_name', - 'first_name', - 'email', - 'pets', - ] - column_default_sort = [('last_name', False), ('first_name', False)] # sort on multiple columns - - # custom filter: each filter in the list is a filter operation (equals, not equals, etc) - # filters with the same name will appear as operations under the same filter - column_filters = [ - FilterEqual(column=User.last_name, name='Last Name'), - FilterLastNameBrown(column=User.last_name, name='Last Name', - options=(('1', 'Yes'), ('0', 'No'))) - ] - inline_models = [(UserInfo, inline_form_options), ] - - # setup create & edit forms so that only 'available' pets can be selected - def create_form(self): - return self._use_filtered_parent( - super(UserAdmin, self).create_form() - ) - - def edit_form(self, obj): - return self._use_filtered_parent( - super(UserAdmin, self).edit_form(obj) - ) - - def _use_filtered_parent(self, form): - form.pets.query_factory = self._get_parent_list - return form - - def _get_parent_list(self): - # only show available pets in the form - return Pet.query.filter_by(available=True).all() - -# Customized Post model admin -class PostAdmin(sqla.ModelView): - column_list = ['id', 'user', 'title', 'date', 'tags'] - column_default_sort = ('date', True) - column_sortable_list = [ - 'id', - 'title', - 'date', - ('user', ('user.last_name', 'user.first_name')), # sort on multiple columns - ] - column_labels = dict(title='Post Title') # Rename 'title' column in list view - column_searchable_list = [ - 'title', - 'tags.name', - 'user.first_name', - 'user.last_name', - ] - column_labels = { - 'title': 'Title', - 'tags.name': 'tags', - 'user.first_name': 'user\'s first name', - 'user.last_name': 'last name', - } - column_filters = [ - 'user', - 'title', - 'date', - 'tags', - filters.FilterLike(Post.title, 'Fixed Title', options=(('test1', 'Test 1'), ('test2', 'Test 2'))), - ] - can_export = True - export_max_rows = 1000 - export_types = ['csv', 'xls'] - - # Pass arguments to WTForms. In this case, change label for text field to - # be 'Big Text' and add required() validator. - form_args = dict( - text=dict(label='Big Text', validators=[validators.data_required()]) - ) - - form_ajax_refs = { - 'user': { - 'fields': (User.first_name, User.last_name) - }, - 'tags': { - 'fields': (Tag.name,), - 'minimum_input_length': 0, # show suggestions, even before any user input - 'placeholder': 'Please select', - 'page_size': 5, - }, - } - - def __init__(self, session): - # Just call parent class with predefined model. - super(PostAdmin, self).__init__(Post, session) - - - - -class TreeView(sqla.ModelView): - form_excluded_columns = ['children', ] - - -class ScreenView(sqla.ModelView): - column_list = ['id', 'width', 'height', - 'number_of_pixels'] # not that 'number_of_pixels' is a hybrid property, not a field - column_sortable_list = ['id', 'width', 'height', 'number_of_pixels'] - - # Flask-admin can automatically detect the relevant filters for hybrid properties. - column_filters = ('number_of_pixels',) -''' - # Create admin -admin = admin.Admin(app, name='Softwaresammlung: Digitale Methoden', template_mode='bootstrap3') +admin = admin.Admin(app, name='SoftwareTools: digital methods', template_mode='bootstrap3') # Add views -admin.add_view(AdvancedSoftwareView(Software, db.session)) -admin.add_view(sqla.ModelView(Feature, db.session, category="Weiteres")) -admin.add_view(sqla.ModelView(License, db.session, category="Weiteres")) -admin.add_view(sqla.ModelView(Link, db.session, category="Weiteres")) -admin.add_view(sqla.ModelView(SoftwareCategory, db.session, category="Weiteres")) -admin.add_sub_category(name="Andere Sammlungen", parent_name="Weiteres") -admin.add_link(MenuLink(name="CRAN-R", url='https://cran.r-project.org/web/views/', category='Andere Sammlungen', target="_blank")) -admin.add_link(MenuLink(name="ROpenSci", url='https://ropensci.org/packages/', category='Andere Sammlungen', target="_blank")) +admin.add_view(AdvancedSoftwareView(Software, db.session, name="SoftwareTool")) +admin.add_view(sqla.ModelView(Feature, db.session, category="Misc")) +admin.add_view(sqla.ModelView(License, db.session, category="Misc")) +admin.add_view(sqla.ModelView(Link, db.session, category="Misc")) +admin.add_view(sqla.ModelView(SoftwareCategory, db.session, category="Misc")) +admin.add_sub_category(name="Other collections", parent_name="Misc") +admin.add_link(MenuLink(name="CRAN-R", url='https://cran.r-project.org/web/views/', category='Other collections', target="_blank")) +admin.add_link(MenuLink(name="ROpenSci", url='https://ropensci.org/packages/', category='Other collections', target="_blank")) @@ -344,12 +230,9 @@ def build_sample_db(): Populate a small db with some example entries. """ - import random - import datetime - db.drop_all() db.create_all() - lic_unknown = License(name="Unbekannt") + lic_unknown = License(name="Unknown") lic_bsd = License(name="BSD") lic_gpl2 = License(name="GPL", version="2.0") lic_gpl3 = License(name="GPL", version="3.0") @@ -359,7 +242,7 @@ def build_sample_db(): lic_mit = License(name="MIT") lic_byncnd3 = License(name="CC BY-NC-ND", version="3.0") lic_ccdl = License(name="CCDL", version="1.0") - lic_prop = License(name="Proprietär") + lic_prop = License(name="Proprietary") db.session.add(lic_gpl3) db.session.add(lic_gpl3) db.session.add(lic_agpl3) @@ -383,25 +266,27 @@ def build_sample_db(): db.session.add(prol_js) db.session.add(prol_c) - cat_tracking = SoftwareCategory(name="datenschutzkonformes Tracking", short_description="Sammlung von Sensordaten/Logdaten oder Nutzungsdaten mit expliziter Einverständnis mittels Software auf dem Gerät.") - cat_scraping = SoftwareCategory(name="Scraping", short_description="Tools im Zusammenhang mit Web-Scraping.") - cat_int = SoftwareCategory(name="Korpusanalyse", short_description="Integrierte Plattformen für die Analyse großer Textcorpora.") - cat_qda = SoftwareCategory(name="QDA-Software", short_description="Computer-gestützte Analyse qualitativer Daten.") - cat_tm = SoftwareCategory(name="Automatisierte Inhaltsanalyse/Text Mining", short_description="") - - cat_senti = SoftwareCategory(name="Sentiment Analysis", short_description="") - cat_topic = SoftwareCategory(name="Topic-Modellierung", short_description="") - cat_visu = SoftwareCategory(name="Visualisierung", short_description="") - cat_kollab_anno = SoftwareCategory(name="Kollaboratives Annotieren", short_description="") - cat_kollab_write = SoftwareCategory(name="Kollaboratives Schreiben", short_description="") - cat_stat = SoftwareCategory(name="Statisik-Programme", short_description="Zur statistischen Modellierung einsetzbare Software.") - cat_repo = SoftwareCategory(name="Forschungsdatenspeicherung", short_description="") - cat_now = SoftwareCategory(name="Nowcasting", short_description="") - cat_net = SoftwareCategory(name="Netzwerkanalysen", short_description="social network analysis") - cat_esmema = SoftwareCategory(name="ESM/EMA-Studien", short_description="Datenerhebung in 'natürlicher' Umgebung.") - cat_transkript = SoftwareCategory(name="Audio-Transkription", short_description="Transkriptionssoftware") - cat_search = SoftwareCategory(name="Suche", short_description="Software im Zusammenhang von erweiterter Suche in großen Textmengen") - cat_misc = SoftwareCategory(name="Weiteres", short_description="Zu speziell zum Einordnen..") + cat_tracking = SoftwareCategory(name="user-consented tracking", short_description="Collection of sensor data on (mobile) devices in accordance with data protection laws.") + cat_scraping = SoftwareCategory(name="scraping", short_description="Tools in the area of web-scraping") + cat_int = SoftwareCategory(name="tools for corpus linguistics", short_description="Integrated platforms for corpus analysis and processing.") + cat_qda = SoftwareCategory(name="computer assisted/aided qualitative data analysis software (CAQDAS)", short_description="assist with qualitative research such as transcription analysis, coding and text interpretation, recursive abstraction, content analysis, discourse analysis, grounded theory methodology, etc.") + cat_tm = SoftwareCategory(name="text mining/natuaral language processing(NLP)", short_description="") + cat_senti = SoftwareCategory(name="sentiment analysis", short_description="") + cat_topic = SoftwareCategory(name="topic-models", short_description="") + cat_visu = SoftwareCategory(name="visualization", short_description="") + cat_kollab_anno = SoftwareCategory(name="collaborative annotation", short_description="") + cat_kollab_write = SoftwareCategory(name="collaborative writing", short_description="") + cat_stat = SoftwareCategory(name="statistical software", short_description="software that helps calcualting with specific statistical models") + cat_repo = SoftwareCategory(name="research data archiving", short_description="") + cat_now = SoftwareCategory(name="nowcasting", short_description="") + cat_net = SoftwareCategory(name="network analysis", short_description="social network analysis") + cat_esmema = SoftwareCategory(name="ESM/EMA surveys", short_description="Datenerhebung in 'natürlicher' Umgebung.") + cat_transkript = SoftwareCategory(name="audio-transcriptions", short_description="software that converts speech into electronic text document.") + cat_search = SoftwareCategory(name="search", short_description="information retrieval in large datasets.") + cat_ocr = SoftwareCategory(name="optical character recognition (OCR)",short_description="OCR is the mechanical or electronic conversion of images of typed, handwritten or printed text into machine-encoded text.") + cat_oe = SoftwareCategory(name="online experiments", short_description="") + cat_misc = SoftwareCategory(name="miscellaneous", short_description="") + db.session.add(cat_tracking) db.session.add(cat_scraping) @@ -449,6 +334,17 @@ def build_sample_db(): db.session.add(Link(software=tool, type="repository", url="https://github.com/audaciouscode/PassiveDataKit-Android", comment="android")) db.session.add(Link(software=tool, type="repository", url="https://github.com/audaciouscode/PassiveDataKit-iOS", comment="iOS")) + tool = Software(name="facepager", + developer="Jakob Jünger and Till Keyling", + maintainer="Jakob Jünger", + softwarecategory=cat_scraping, + architecture="package", + license=lic_mit, + programminglanguages=[prol_py]) + db.session.add(tool) + db.session.add(Link(software=tool, type="wiki", url="https://github.com/strohne/Facepager", comment="")) + db.session.add(Link(software=tool, type="repository", url="https://github.com/strohne/Facepager", comment="")) + tool = Software(name="Scrapy", developer="", maintainer="", @@ -857,6 +753,18 @@ def build_sample_db(): db.session.add(Link(software=tool, type="website", url="https://gephi.org/", comment="")) db.session.add(Link(software=tool, type="repository", url="https://github.com/gephi/gephi/", comment="")) + tool = Software(name="scikit-image", + short_description="scikit-image is a collection of algorithms for image processing. It is available free of charge and free of restriction. We pride ourselves on high-quality, peer-reviewed code, written by an active community of volunteers.", + developer="Stéfan van der Walt, Johannes L. Schönberger, Juan Nunez-Iglesias, François Boulogne, Joshua D. Warner, Neil Yager, Emmanuelle Gouillart, Tony Yu, and the scikit-image contributors", + maintainer="Stéfan van der Walt, Johannes L. Schönberger, Juan Nunez-Iglesias, François Boulogne, Joshua D. Warner, Neil Yager, Emmanuelle Gouillart, Tony Yu, and the scikit-image contributors", + softwarecategory=cat_visu, + architecture="package", + license=lic_bsd, + programminglanguages=[prol_py]) + db.session.add(tool) + db.session.add(Link(software=tool, type="website", url="https://scikit-image.org/", comment="")) + db.session.add(Link(software=tool, type="repository", url="https://github.com/scikit-image/scikit-image", comment="")) + tool = Software(name="CATMA", short_description="CATMA (Computer Assisted Text Markup and Analysis) is a practical and intuitive tool for text researchers. In CATMA users can combine the hermeneutic, ‘undogmatic’ and the digital, taxonomy based approach to text and corpora—as a single researcher, or in real-time collaboration with other team members.", developer="", @@ -939,7 +847,7 @@ def build_sample_db(): license=lic_prop, programminglanguages=[]) db.session.add(tool) - db.session.add(Link(software=tool, type="website", url="https://www.rrz.uni-hamburg.de/services/software/software-thematisch/statistik/stata.html", comment = "uhh")) + db.session.add(Link(software=tool, type="website", url="https://www.rrz.uni-hamburg.de/services/software/software-thematisch/statistik/spss-netzlizenz.html", comment = "uhh")) tool = Software(name="STATA", @@ -951,7 +859,7 @@ def build_sample_db(): license=lic_prop, programminglanguages=[]) db.session.add(tool) - db.session.add(Link(software=tool, type="website", url="https://www.rrz.uni-hamburg.de/services/software/software-thematisch/statistik/spss-netzlizenz.html", comment = "uhh")) + db.session.add(Link(software=tool, type="website", url="https://www.rrz.uni-hamburg.de/services/software/software-thematisch/statistik/stata.html", comment = "uhh")) tool = Software(name="Nowcasting", short_description="", @@ -1079,6 +987,40 @@ def build_sample_db(): db.session.add(Link(software=tool, type="website", url="", comment="")) db.session.add(Link(software=tool, type="repository", url="https://github.com/EXMARaLDA/exmaralda", comment="")) + tool = Software(name="tesseract", + short_description="Tesseract is an open source text recognizer (OCR) Engine, available under the Apache 2.0 license. It can be used directly, or (for programmers) using an API to extract printed text from images. It supports a wide variety of languages.", + developer="Google, HP Inc.", + maintainer="Ray Smith u. a. ", + softwarecategory=cat_ocr, + architecture="package", + license=lic_apache2, + programminglanguages=[prol_py]) + db.session.add(tool) + db.session.add(Link(software=tool, type="repository", url="https://github.com/tesseract-ocr/tesseract", comment="")) + + tool = Software(name="nodeGame", + short_description="NodeGame is a free, open source JavaScript/HTML5 framework for conducting synchronous experiments online and in the lab directly in the browser window. It is specifically designed to support behavioral research along three dimensions: larger group sizes, real-time (but also discrete time) experiments, batches of simultaneous experiments.", + developer="Stefan Balietti", + maintainer="Stefan Balietti", + softwarecategory=cat_oe, + architecture="package", + license=lic_mit, + programminglanguages=[prol_js]) + db.session.add(tool) + db.session.add(Link(software=tool, type="website", url="https://nodegame.org/", comment="")) + db.session.add(Link(software=tool, type="repository", url="https://github.com/nodeGame", comment="")) + + tool = Software(name="scikit-learn", + short_description="Scikit-learn is a free software machine learning library for the Python programming language. It features various classification, regression and clustering algorithms including support vector machines, random forests, gradient boosting, k-means and DBSCAN, and is designed to interoperate with the Python numerical and scientific libraries NumPy and SciPy.", + developer="Pedregosa, F. and Varoquaux, G. and Gramfort, A. and Michel, V. and Thirion, B. and Grisel, O. and Blondel, M. and Prettenhofer, P. and Weiss, R. and Dubourg, V. and Vanderplas, J. and Passos, A. and Cournapeau, D. and Brucher, M. and Perrot, M. and Duchesnay, E.", + maintainer="Pedregosa, F. and Varoquaux, G. and Gramfort, A. and Michel, V. and Thirion, B. and Grisel, O. and Blondel, M. and Prettenhofer, P. and Weiss, R. and Dubourg, V. and Vanderplas, J. and Passos, A. and Cournapeau, D. and Brucher, M. and Perrot, M. and Duchesnay, E.", + softwarecategory=cat_misc, + architecture="package", + license=lic_bsd, + programminglanguages=[prol_py]) + db.session.add(tool) + db.session.add(Link(software=tool, type="website", url="https://scikit-learn.org/stable/index.html", comment="")) + db.session.add(Link(software=tool, type="repository", url="https://github.com/scikit-learn/scikit-learn", comment="")) ''' tool = Software(name="", diff --git a/sample_db.sqlite b/sample_db.sqlite index 70a3bda9555a978394356aff339af7e3870bd091..71c57ac22da4c8b03f75d19b5e73b215f671f0a8 100644 GIT binary patch delta 7836 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 S%$g}alfxG#uxOTMWB>p$i<ajA delta 4411 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 K;A7-x)C2(C)8SbF diff --git a/templates/export/softwares.jinja2 b/templates/export/softwares.jinja2 index d96d39f..c355f74 100644 --- a/templates/export/softwares.jinja2 +++ b/templates/export/softwares.jinja2 @@ -1,3 +1,9 @@ +:toc: +:toclevels: 8 +:toc-title: Categories (work in progress: this list is preliminary and will be updated continuously) +:sectnums: +:sectnumlevels: 8 + {% for softwarecategory in softwareincategory %} == {{ softwarecategory[0].name }} _{{softwarecategory[0].short_description}}_ -- GitLab