Compare commits
13
Commits
48ca31a47b
...
newsletter
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
811b7c5453 | ||
|
|
7ed667d043 | ||
|
|
f5980566ae | ||
|
|
3c7005afaf | ||
|
|
df5d420505 | ||
|
|
4a753ff6c9 | ||
|
|
7d0350d452 | ||
|
|
d01ed0085c | ||
|
|
5dc4b05a8f | ||
|
|
ca6655d535 | ||
|
|
26cbed89c8 | ||
|
|
aea40fe98a | ||
|
|
49c98b5cb6 |
No files matched your search
@@ -0,0 +1,5 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
# This will make sure celery is always imported when
|
||||
# Django starts so that shared_task will use this app.
|
||||
from .celeryapp import app as celery_app
|
||||
__all__ = ['celery_app']
|
||||
@@ -4,6 +4,8 @@ from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from .models import Post, CustomUser
|
||||
from .models import ScheduledReport, ReportRecipient, ScheduledReportGroup
|
||||
from .forms import ScheduledReportForm
|
||||
|
||||
|
||||
class CustomUserInline(admin.StackedInline):
|
||||
@@ -20,3 +22,43 @@ admin.site.unregister(User)
|
||||
admin.site.register(User, UserAdmin)
|
||||
|
||||
admin.site.register(Post)
|
||||
|
||||
|
||||
class ReportRecipientAdmin(admin.TabularInline):
|
||||
model = ReportRecipient
|
||||
class ScheduledReportAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
List display for Scheduled reports in Django admin
|
||||
"""
|
||||
model = ScheduledReport
|
||||
list_display = ('id', 'get_recipients')
|
||||
inlines = [
|
||||
ReportRecipientAdmin
|
||||
]
|
||||
form = ScheduledReportForm
|
||||
def get_recipients(self, model):
|
||||
recipients = model.reportrecep.all().values_list('email', flat=True)
|
||||
if not recipients:
|
||||
return 'No recipients added'
|
||||
recipient_list = ''
|
||||
for recipient in recipients:
|
||||
recipient_list = recipient_list + recipient + ', '
|
||||
return recipient_list[:-2]
|
||||
get_recipients.short_description = 'Recipients'
|
||||
get_recipients.allow_tags = True
|
||||
class ScheduledReportGroupAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
List display for ScheduledReportGroup Admin
|
||||
"""
|
||||
model = ScheduledReportGroup
|
||||
list_display = ('get_scheduled_report_name','get_report_name')
|
||||
def get_scheduled_report_name(self, model):
|
||||
return model.scheduled_report.subject
|
||||
def get_report_name(self, model):
|
||||
return model.report.name
|
||||
get_scheduled_report_name.short_description = "Scheduled Report Name"
|
||||
get_report_name.short_description = "Report Name"
|
||||
show_change_link = True
|
||||
get_report_name.allow_tags = True
|
||||
admin.site.register(ScheduledReport, ScheduledReportAdmin)
|
||||
admin.site.register(ScheduledReportGroup, ScheduledReportGroupAdmin)
|
||||
@@ -0,0 +1,13 @@
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
from celery import Celery
|
||||
# set the default Django settings module for the 'celery' program.
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
|
||||
from django.conf import settings
|
||||
|
||||
app = Celery('application')
|
||||
# Using a string here means the worker don't have to serialize
|
||||
# the configuration object to child processes.
|
||||
app.config_from_object('django.conf:settings')
|
||||
# Load task modules from all registered Django app configs.
|
||||
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
|
||||
@@ -0,0 +1,57 @@
|
||||
from datetime import datetime, timedelta
|
||||
from django.core.mail import send_mail
|
||||
from django.template import Template, Context
|
||||
from django.http import HttpResponse
|
||||
from django.conf import settings
|
||||
from .models import ScheduledReport, ScheduledReportGroup, ReportRecipient
|
||||
class ScheduledReportConfig(object):
|
||||
def __init__(self, scheduled_report):
|
||||
"""
|
||||
Expects a scheduled report object and inititializes
|
||||
its own scheduled_report attribute with it
|
||||
"""
|
||||
self.scheduled_report = scheduled_report
|
||||
def get_report_config(self):
|
||||
"""
|
||||
Returns the configuration related to a scheduled report, needed
|
||||
to populate the email
|
||||
"""
|
||||
return {
|
||||
"template_context": self._get_related_reports_data(),
|
||||
"recipients": self._get_report_recipients()
|
||||
}
|
||||
def _get_related_reports_data(self):
|
||||
"""
|
||||
Returns the list of reports data which needs to be sent out in a scheduled report
|
||||
"""
|
||||
pass
|
||||
def _get_report_recipients(self):
|
||||
"""
|
||||
Returns the recipient list for a scheduled report
|
||||
"""
|
||||
pass
|
||||
def create_email_data(content=None):
|
||||
content = '''
|
||||
|
||||
|
||||
''' + str(content) + ''''''
|
||||
return content
|
||||
def send_emails():
|
||||
current_time = datetime.utcnow()
|
||||
scheduled_reports = ScheduledReport.objects.filter(next_run_at__lt = current_time)
|
||||
for scheduled_report in scheduled_reports:
|
||||
report_config = ScheduledReportConfig(scheduled_report).get_report_config()
|
||||
""" Specify the template path you want to send out in the email. """
|
||||
template = Template(create_email_data('path/to/your/email_template.html'))
|
||||
""" //Create your email html using Django's context processor """
|
||||
report_template = template.render(Context(report_config['template_context']))
|
||||
scheduled_report.save()
|
||||
if not scheduled_report.subject:
|
||||
""" Handle exception for subject not provided """
|
||||
if not report_config['recipients']:
|
||||
""" Handle exception for recipients not provided """
|
||||
send_mail(
|
||||
scheduled_report.subject, 'Here is the message.',
|
||||
settings.EMAIL_HOST_USER, report_config['recipients'],
|
||||
fail_silently=False, html_message=report_template
|
||||
)
|
||||
@@ -1,8 +1,16 @@
|
||||
from django import forms
|
||||
from datetime import datetime
|
||||
|
||||
from .models import Post, CustomUser
|
||||
from django.forms import ModelForm, ValidationError
|
||||
from taggit.forms import *
|
||||
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
|
||||
|
||||
from datetime import datetime
|
||||
from croniter import croniter
|
||||
from django.forms import ModelForm, ValidationError
|
||||
from .models import ScheduledReport
|
||||
|
||||
class PostForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Post
|
||||
@@ -13,3 +21,27 @@ class NewTagForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = CustomUser
|
||||
fields = ['m_tags']
|
||||
|
||||
|
||||
class ScheduledReportForm(ModelForm):
|
||||
class Meta:
|
||||
model = ScheduledReport
|
||||
fields = ['subject', 'cron_expression']
|
||||
fields = ['subject', 'cron_expression']
|
||||
help_texts = {'cron_expression': 'Scheduled time is considered in UTC'}
|
||||
def clean(self):
|
||||
cleaned_data = super(ScheduledReportForm, self).clean()
|
||||
cron_expression = cleaned_data.get("cron_expression")
|
||||
try:
|
||||
iter = croniter(cron_expression, datetime.now())
|
||||
except:
|
||||
raise ValidationError("Incorrect cron expression:\
|
||||
The information you must include is (in order of appearance):\
|
||||
A number (or list of numbers, or range of numbers), m, representing the minute of the hour\
|
||||
A number (or list of numbers, or range of numbers), h, representing the hour of the day\
|
||||
A number (or list of numbers, or range of numbers), dom, representing the day of the month\
|
||||
A number (or list, or range), or name (or list of names), mon, representing the month of the year\
|
||||
A number (or list, or range), or name (or list of names), dow, representing the day of the week\
|
||||
The asterisks (*) in our entry tell cron that for that unit of time, the job should be run every.\
|
||||
Eg. */5 * * * * cron for executing every 5 mins")
|
||||
return cleaned_data
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.1 on 2018-10-19 14:45
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('application', '0004_auto_20180831_1019'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='customuser',
|
||||
old_name='mytags',
|
||||
new_name='tags',
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,51 @@
|
||||
# Generated by Django 2.1 on 2018-10-21 11:47
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('application', '0005_auto_20181019_1645'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Report',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('report_text', models.TextField()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ReportRecipient',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('email', models.EmailField(max_length=254)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ScheduledReport',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('subject', models.CharField(max_length=200)),
|
||||
('last_run_at', models.DateTimeField(blank=True, null=True)),
|
||||
('next_run_at', models.DateTimeField(blank=True, null=True)),
|
||||
('cron_expression', models.CharField(max_length=200)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ScheduledReportGroup',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('report', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='report', to='application.Report')),
|
||||
('scheduled_report', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='relatedscheduledreport', to='application.ScheduledReport')),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='reportrecipient',
|
||||
name='scheduled_report',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reportrecep', to='application.ScheduledReport'),
|
||||
),
|
||||
]
|
||||
+42
-3
@@ -2,12 +2,15 @@ from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils import timezone
|
||||
from taggit.managers import TaggableManager
|
||||
from datetime import datetime
|
||||
from croniter import croniter
|
||||
|
||||
|
||||
|
||||
class CustomUser(models.Model):
|
||||
user = models.OneToOneField('auth.User', null = True, on_delete=models.CASCADE)
|
||||
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
|
||||
tags = TaggableManager()
|
||||
|
||||
|
||||
class Post(models.Model):
|
||||
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
|
||||
title = models.CharField(max_length=200)
|
||||
@@ -23,4 +26,40 @@ class Post(models.Model):
|
||||
self.save()
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
return self.title
|
||||
|
||||
class Report(models.Model):
|
||||
report_text = models.TextField()
|
||||
|
||||
class ScheduledReport(models.Model):
|
||||
"""
|
||||
Contains email subject and cron expression,to evaluate when the email has to be sent
|
||||
"""
|
||||
subject = models.CharField(max_length=200)
|
||||
last_run_at = models.DateTimeField(null=True, blank=True)
|
||||
next_run_at = models.DateTimeField(null=True, blank=True)
|
||||
cron_expression = models.CharField(max_length=200)
|
||||
def save(self, *args, **kwargs):
|
||||
"""
|
||||
function to evaluate "next_run_at" using the cron expression, so that it is updated once the report is sent.
|
||||
"""
|
||||
self.last_run_at = datetime.now()
|
||||
iter = croniter(self.cron_expression, self.last_run_at)
|
||||
self.next_run_at = iter.get_next(datetime)
|
||||
super(ScheduledReport, self).save(*args, **kwargs)
|
||||
def __unicode__(self):
|
||||
return self.subject
|
||||
|
||||
class ScheduledReportGroup(models.Model):
|
||||
"""
|
||||
Many to many mapping between reports which will be sent out in a scheduled report
|
||||
"""
|
||||
report = models.ForeignKey(Report, related_name='report', on_delete=models.CASCADE)
|
||||
scheduled_report = models.ForeignKey(ScheduledReport,
|
||||
related_name='relatedscheduledreport', on_delete=models.CASCADE)
|
||||
class ReportRecipient(models.Model):
|
||||
"""
|
||||
Stores all the recipients of the given scheduled report
|
||||
"""
|
||||
email = models.EmailField()
|
||||
scheduled_report = models.ForeignKey(ScheduledReport, related_name='reportrecep', on_delete=models.CASCADE)
|
||||
@@ -0,0 +1,7 @@
|
||||
from celery.task.schedules import crontab
|
||||
from celery.decorators import periodic_task
|
||||
from .email_service import send_emails
|
||||
# this will run every minute, see http://celeryproject.org/docs/reference/celery.task.schedules.html#celery.task.schedules.crontab
|
||||
@periodic_task(run_every=crontab(hour="*", minute="*", day_of_week="*"))
|
||||
def trigger_emails():
|
||||
send_emails()
|
||||
@@ -37,6 +37,9 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'student_page' %}">Studentenansicht</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'blog_search_list_view' %}">Suche</a>
|
||||
</li>
|
||||
{% elif user.is_staff %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'logout' %}">Administration</a>
|
||||
|
||||
@@ -1,32 +1,27 @@
|
||||
{% extends "base.html" %} {% block content %}
|
||||
{% load taggit_templatetags2_tags %}
|
||||
{% get_taglist as tags for 'application.post' %}
|
||||
<div id="">
|
||||
<ul>
|
||||
{% for tag in tags %}
|
||||
<li>{{tag}} ({{tag.num_times}})
|
||||
</li>
|
||||
{{ result }}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% include "taggit_templatetags2/tagcanvas_include_js_static.html" %}
|
||||
|
||||
<div id="tag-cloud">
|
||||
</div>
|
||||
|
||||
{% get_tagcloud as tags for 'application' %}
|
||||
{% include_tagcloud 'application.Post' %}
|
||||
<form type="get" action="." style="margin: 0">
|
||||
<input id="search_box" type="text" name="search_box" placeholder="Search..." >
|
||||
<button id="search_submit" type="submit" >Submit</button>
|
||||
<input id="search_box" type="text" name="search_box" placeholder="Search...">
|
||||
<button id="search_submit" type="submit">Suchen</button>
|
||||
</form>
|
||||
<div>
|
||||
<ul>
|
||||
{% for tag in tags %}
|
||||
<li>
|
||||
{{tag}}
|
||||
</li>
|
||||
{% endfor %}
|
||||
|
||||
</ul>
|
||||
{% for post in posts %}
|
||||
<div class="post">
|
||||
<div class="date">
|
||||
{{ post.published_date }}
|
||||
</div>
|
||||
<h1>
|
||||
<a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a>
|
||||
</h1>
|
||||
<p>{{ post.text|linebreaks }}</p>
|
||||
Tags: {% for tag in post.tags.all %}
|
||||
<a href="{% url 'post_list_by_tag' tag.slug %}">{{ tag.name }}</a>
|
||||
{% if not forloop.last %}, {% endif %} {% endfor %} <p>
|
||||
{{ post.author }}
|
||||
</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -12,18 +12,11 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
</div>
|
||||
<form id="searchform" action="{% url 'blog_search_list_view' %}" method="get" accept-charset="utf-8">
|
||||
<button class="searchbutton" type="submit">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
<input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search">
|
||||
</form>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered table-hover">
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div {% if message.tags %} class="{{ message.tags }}" {% endif %}>{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<form class="post-form" method="post">
|
||||
{% csrf_token %} {{form.as_p}}
|
||||
<button type="submit" class="save btn btn-outline-dark">Save</button>
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
{% extends "base.html" %} {% block content %} {% load taggit_templatetags2_tags %}
|
||||
{% extends "base.html" %} {% block content %}
|
||||
{% load taggit_templatetags2_tags %}
|
||||
|
||||
|
||||
<div id="">
|
||||
Your tags:
|
||||
<ul>
|
||||
{% for tag in tags %}
|
||||
<li>
|
||||
<a href="{% url 'post_list_by_tag' tag.slug %}">{{ tag }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<div>
|
||||
</div>
|
||||
<div>
|
||||
{{ tags }} {{ u }}
|
||||
</div>
|
||||
<div>
|
||||
from List: {% for tag in tags %}
|
||||
|
||||
{% for tag in posts %}
|
||||
<p>{{ tag.name }} </p>{% endfor %}{% endfor %}
|
||||
{% for post in posts %}
|
||||
<div class="post">
|
||||
<div class="date">
|
||||
{{ post.published_date }}
|
||||
</div>
|
||||
<h1>
|
||||
<a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a>
|
||||
</h1>
|
||||
<p>{{ post.text|linebreaks }}</p>
|
||||
Tags: {% for tag in post.tags.all %}
|
||||
<a href="{% url 'post_list_by_tag' tag.slug %}">{{ tag.name }}</a>
|
||||
{% if not forloop.last %}, {% endif %} {% endfor %} <p>
|
||||
{{ post.author }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,20 @@
|
||||
{% extends 'base.html' %} {% block content %}
|
||||
{% if tag %} Posts tagged with "{{ tag.name }}" {% endif %}
|
||||
{% for post in posts %}
|
||||
<div class="post">
|
||||
<div class="date">
|
||||
{{ post.published_date }}
|
||||
</div>
|
||||
<h1>
|
||||
<a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a>
|
||||
</h1>
|
||||
<p>{{ post.text|linebreaks }}</p>
|
||||
Tags: {% for tag in post.tags.all %}
|
||||
<a href="{% url 'student_page_remove' tag.slug %}">{{ tag.name }}</a>
|
||||
{% if not forloop.last %}, {% endif %} {% endfor %} <p>
|
||||
{{ post.author }}
|
||||
</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,7 +1,11 @@
|
||||
from django.conf import settings
|
||||
from django.conf.urls import url
|
||||
from django.conf.urls import include
|
||||
from django.urls import path
|
||||
from taggit_templatetags2 import urls as taggit_templatetags2_urls
|
||||
from . import views
|
||||
import debug_toolbar
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.post_list, name='post_list'),
|
||||
@@ -9,6 +13,7 @@ urlpatterns = [
|
||||
url(r'^taglist/$', views.tag_list, name='tag_list'),
|
||||
url(r'^student/', views.student_page, name='student_page'),
|
||||
url(r'^search/', views.blog_search_list_view, name='blog_search_list_view'),
|
||||
url(r'^search/result/$', views.blog_search_list_view, name='post_list_by_search'),
|
||||
url(r'^post/(?P<pk>\d+)/$', views.post_detail, name='post_detail'),
|
||||
url(r'^post/new/$', views.post_new, name='post_new'),
|
||||
url(r'^post/(?P<pk>\d+)/edit/$', views.post_edit, name='post_edit'),
|
||||
@@ -17,5 +22,11 @@ urlpatterns = [
|
||||
url(r'^post/(?P<pk>\d+)/remove/$', views.post_remove, name='post_remove'),
|
||||
url(r'^student/(?P<slug>[-\w]+)/remove/$', views.tag_remove, name='tag_remove'),
|
||||
url(r'^tags/', include('taggit_templatetags2.urls')),
|
||||
url(r'^newsletter/', include('newsletter.urls')),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
import debug_toolbar
|
||||
urlpatterns += [
|
||||
url(r'^__debug__/', include(debug_toolbar.urls)),
|
||||
]
|
||||
+32
-37
@@ -12,18 +12,19 @@ from django.db.models import Q
|
||||
import sys
|
||||
import collections
|
||||
from taggit_templatetags2.views import TagCanvasListView
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib import messages
|
||||
|
||||
|
||||
|
||||
import logging
|
||||
import mysite.settings
|
||||
import operator
|
||||
|
||||
|
||||
# Create your views here.
|
||||
|
||||
|
||||
def navlogin(request):
|
||||
|
||||
log = logging.getLogger('medinf')
|
||||
log = logging.getLogger('mysite')
|
||||
logout(request)
|
||||
error = ""
|
||||
if request.POST:
|
||||
@@ -47,11 +48,12 @@ def navlogin(request):
|
||||
|
||||
@login_required
|
||||
def post_list(request, slug=None):
|
||||
log = logging.getLogger('mysite')
|
||||
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
|
||||
if slug:
|
||||
tag = get_object_or_404(Tag, slug=slug)
|
||||
posts= posts.filter(tags__in=[tag])
|
||||
page = request.GET.get('page')
|
||||
posts = posts.filter(tags__in=[tag])
|
||||
log.info(posts)
|
||||
return render(request, 'post_list.html', locals())
|
||||
|
||||
|
||||
@@ -135,27 +137,28 @@ def student_page(request):
|
||||
obj.user = request.user
|
||||
obj.save()
|
||||
m_tags = form.cleaned_data['m_tags']
|
||||
obj.tags.add(*m_tags)
|
||||
form.save_m2m()
|
||||
return redirect('/student/')
|
||||
|
||||
tags = Tag.objects.all()
|
||||
if m_tags in tags:
|
||||
obj.tags.add(*m_tags)
|
||||
form.save_m2m()
|
||||
return redirect('/student/')
|
||||
else:
|
||||
messages.info(request, 'Sorry !! Den Tag den du suchst gibt es leider nicht!')
|
||||
else:
|
||||
form = NewTagForm()
|
||||
return render(request, 'student_page.html', {'form':form})
|
||||
|
||||
@login_required
|
||||
def tag_list(request):
|
||||
u = CustomUser.objects.get(user=request.user)
|
||||
tags= Tag.objects.filter(customuser=u)
|
||||
arr=[]
|
||||
arr.append(tags)
|
||||
"""
|
||||
for tag in tags:
|
||||
arr.append(str(tag))
|
||||
"""
|
||||
listing = list(arr)
|
||||
return render(request, 'tag_list.html', {'tags':tags})
|
||||
|
||||
log = logging.getLogger('mysite')
|
||||
u = User.objects.get(username=request.user)
|
||||
if u:
|
||||
tags_user = Tag.objects.filter(customuser__user = u)
|
||||
log.info(tags_user)
|
||||
for tag in tags_user:
|
||||
posts = Post.objects.filter(tags__in=[tag]).order_by('-published_date')
|
||||
log.info(posts)
|
||||
return render(request, 'tag_list.html', locals())
|
||||
|
||||
class TagSearch(TagCanvasListView):
|
||||
template_name = 'blog_search_list_view.html'
|
||||
@@ -178,22 +181,14 @@ class TagSearch(TagCanvasListView):
|
||||
cObj = cObj.order_by(var_get_order_by)
|
||||
return cObj
|
||||
|
||||
def blog_search_list_view(request):
|
||||
return render(request, 'blog_search_list_view.html', {})
|
||||
def blog_search_list_view(request):
|
||||
log = logging.getLogger('mysite')
|
||||
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
|
||||
if request.method == 'GET':
|
||||
search_query = request.GET.get('search_box', None)
|
||||
log.info(search_query)
|
||||
posts = posts.filter(tags__name__in=[search_query])
|
||||
return render(request, 'blog_search_list_view.html', locals())
|
||||
|
||||
def tag_cloud(request):
|
||||
return render(request, 'tag_cloud.html', {})
|
||||
|
||||
"""
|
||||
@login_required
|
||||
def post_of_user_list(request):
|
||||
u= CustomUser.objects.get(user=request.user)
|
||||
tag =[]
|
||||
|
||||
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
|
||||
if slug:
|
||||
tag = get_object_or_404(Tag, slug=slug)
|
||||
posts= posts.filter(tags__in=[tag])
|
||||
page = request.GET.get('page')
|
||||
return render(request, 'post_list.html', locals())
|
||||
"""
|
||||
Submodule
+1
Submodule croniter added at 3273cbc777.
@@ -24,8 +24,9 @@
|
||||
\babel@aux{german}{}
|
||||
\@input{abstract/abstract.aux}
|
||||
\HyPL@Entry{2<</S/r>>}
|
||||
\@input{chapters/einleitung.aux}
|
||||
\HyPL@Entry{6<</S/D>>}
|
||||
\@writefile{toc}{\contentsline {chapter}{Abbildungsverzeichnis}{1}{chapter*.4}}
|
||||
\@input{chapters/einleitung.aux}
|
||||
\@input{chapters/framework.aux}
|
||||
\@input{chapters/prototyp.aux}
|
||||
\@input{chapters/ergebnis.aux}
|
||||
@@ -34,8 +35,13 @@
|
||||
\bibstyle{alpha}
|
||||
\citation{*}
|
||||
\bibdata{references/References_2}
|
||||
\bibcite{Verdam}{{Lei13}{}{{}}{{}}}
|
||||
\bibcite{Dixit}{{Dix18}{}{{}}{{}}}
|
||||
\bibcite{Python}{{Fou18}{}{{}}{{}}}
|
||||
\bibcite{Gaynor}{{Gay10}{}{{}}{{}}}
|
||||
\bibcite{Herzog}{{Her16}{}{{}}{{}}}
|
||||
\bibcite{King}{{Kin17}{}{{}}{{}}}
|
||||
\bibcite{Leipner}{{Lei13}{}{{}}{{}}}
|
||||
\bibcite{Ndukwe}{{Ndu17}{}{{}}{{}}}
|
||||
\bibcite{Shelest}{{She09}{}{{}}{{}}}
|
||||
\providecommand\NAT@force@numbers{}\NAT@force@numbers
|
||||
\@writefile{toc}{\contentsline {chapter}{Referenzen}{11}{chapter*.4}}
|
||||
\@writefile{toc}{\contentsline {chapter}{Referenzen}{19}{chapter*.11}}
|
||||
@@ -1,6 +1,40 @@
|
||||
\begin{thebibliography}{Ndu17}
|
||||
|
||||
\bibitem[Lei13]{Verdam}
|
||||
\bibitem[Dix18]{Dixit}
|
||||
Chitrank Dixit.
|
||||
\newblock Pep-8 tutorial: Code standards in python.
|
||||
\newblock 2018.
|
||||
\newblock
|
||||
https://www.datacamp.com/community/tutorials/pep8-tutorial-python-code.
|
||||
|
||||
\bibitem[Fou18]{Python}
|
||||
Python~Software Foundation.
|
||||
\newblock Virtual environments and packages.
|
||||
\newblock 2018.
|
||||
\newblock https://docs.python.org/3/tutorial/venv.html.
|
||||
|
||||
\bibitem[Gay10]{Gaynor}
|
||||
Alex Gaynor.
|
||||
\newblock Exploring django-taggit’s data model.
|
||||
\newblock 2010.
|
||||
\newblock https://django-taggit.readthedocs.io/en/latest/getting\_started.
|
||||
|
||||
\bibitem[Her16]{Herzog}
|
||||
Stephan Herzog.
|
||||
\newblock Model view controller, model view presenter, and model view viewmodel
|
||||
design patterns.
|
||||
\newblock 2016.
|
||||
\newblock
|
||||
https://medium.com/sthzg/a-short-exploration-of-django-taggit-bb869ea5051f.
|
||||
|
||||
\bibitem[Kin17]{King}
|
||||
Adam King.
|
||||
\newblock Django middlewares and the request/response cycle.
|
||||
\newblock 2017.
|
||||
\newblock
|
||||
https://medium.com/zeitcode/django-middlewares-and-the-request-response-cycle-fcbf8efb903f.
|
||||
|
||||
\bibitem[Lei13]{Leipner}
|
||||
Ingo Leipner.
|
||||
\newblock Stress für beschäftigte: Wie kann man die e-mail-flut
|
||||
bekämpfen.
|
||||
|
||||
@@ -11,48 +11,53 @@ A level-1 auxiliary file: chapters/ausblick.aux
|
||||
A level-1 auxiliary file: chapters/fazit.aux
|
||||
The style file: alpha.bst
|
||||
Database file #1: ../references/References_2.bib
|
||||
Warning--empty journal in Verdam
|
||||
Warning--empty journal in Dixit
|
||||
Warning--empty journal in Python
|
||||
Warning--empty journal in Gaynor
|
||||
Warning--empty journal in Herzog
|
||||
Warning--empty journal in King
|
||||
Warning--empty journal in Leipner
|
||||
Warning--empty journal in Ndukwe
|
||||
Warning--empty journal in Shelest
|
||||
You've used 3 entries,
|
||||
You've used 8 entries,
|
||||
2543 wiz_defined-function locations,
|
||||
584 strings with 5442 characters,
|
||||
and the built_in function-call counts, 841 in all, are:
|
||||
= -- 81
|
||||
> -- 24
|
||||
< -- 3
|
||||
+ -- 6
|
||||
- -- 6
|
||||
* -- 41
|
||||
:= -- 155
|
||||
add.period$ -- 12
|
||||
call.type$ -- 3
|
||||
change.case$ -- 15
|
||||
chr.to.int$ -- 3
|
||||
cite$ -- 6
|
||||
duplicate$ -- 42
|
||||
empty$ -- 61
|
||||
format.name$ -- 12
|
||||
if$ -- 161
|
||||
611 strings with 6085 characters,
|
||||
and the built_in function-call counts, 2196 in all, are:
|
||||
= -- 216
|
||||
> -- 64
|
||||
< -- 8
|
||||
+ -- 16
|
||||
- -- 16
|
||||
* -- 106
|
||||
:= -- 390
|
||||
add.period$ -- 32
|
||||
call.type$ -- 8
|
||||
change.case$ -- 40
|
||||
chr.to.int$ -- 8
|
||||
cite$ -- 16
|
||||
duplicate$ -- 112
|
||||
empty$ -- 161
|
||||
format.name$ -- 32
|
||||
if$ -- 426
|
||||
int.to.chr$ -- 1
|
||||
int.to.str$ -- 0
|
||||
missing$ -- 3
|
||||
newline$ -- 21
|
||||
num.names$ -- 9
|
||||
pop$ -- 18
|
||||
missing$ -- 8
|
||||
newline$ -- 51
|
||||
num.names$ -- 24
|
||||
pop$ -- 48
|
||||
preamble$ -- 1
|
||||
purify$ -- 18
|
||||
purify$ -- 48
|
||||
quote$ -- 0
|
||||
skip$ -- 33
|
||||
skip$ -- 88
|
||||
stack$ -- 0
|
||||
substring$ -- 21
|
||||
substring$ -- 56
|
||||
swap$ -- 0
|
||||
text.length$ -- 3
|
||||
text.prefix$ -- 3
|
||||
text.length$ -- 8
|
||||
text.prefix$ -- 8
|
||||
top$ -- 0
|
||||
type$ -- 24
|
||||
warning$ -- 3
|
||||
while$ -- 6
|
||||
width$ -- 5
|
||||
write$ -- 41
|
||||
(There were 3 warnings)
|
||||
type$ -- 64
|
||||
warning$ -- 8
|
||||
while$ -- 16
|
||||
width$ -- 10
|
||||
write$ -- 106
|
||||
(There were 8 warnings)
|
||||
@@ -0,0 +1,13 @@
|
||||
\babel@toc {german}{}
|
||||
\babel@toc {german}{}
|
||||
\addvspace {10\p@ }
|
||||
\addvspace {10\p@ }
|
||||
\contentsline {figure}{\numberline {2.1}{\ignorespaces Vereinfachter MVP\relax }}{6}{figure.caption.5}
|
||||
\contentsline {figure}{\numberline {2.2}{\ignorespaces Request-Response-Kreislauf des Django Frameworks\relax }}{7}{figure.caption.6}
|
||||
\contentsline {figure}{\numberline {2.3}{\ignorespaces Erstellen der virtuelle Umgebung im Terminal\relax }}{8}{figure.caption.7}
|
||||
\contentsline {figure}{\numberline {2.4}{\ignorespaces Beispiel eines LDAP-Trees\relax }}{9}{figure.caption.8}
|
||||
\contentsline {figure}{\numberline {2.5}{\ignorespaces Einbindung von Bootstrap in einer HTML-Datei\relax }}{11}{figure.caption.9}
|
||||
\contentsline {figure}{\numberline {2.6}{\ignorespaces Bootstrap-Klassen in HTML-Tag\relax }}{12}{figure.caption.10}
|
||||
\addvspace {10\p@ }
|
||||
\addvspace {10\p@ }
|
||||
\addvspace {10\p@ }
|
||||
@@ -1,4 +1,4 @@
|
||||
This is XeTeX, Version 3.14159265-2.6-0.99999 (TeX Live 2018) (preloaded format=xelatex 2018.6.7) 28 SEP 2018 16:57
|
||||
This is XeTeX, Version 3.14159265-2.6-0.99999 (TeX Live 2018) (preloaded format=xelatex 2018.6.7) 15 OCT 2018 21:49
|
||||
entering extended mode
|
||||
\write18 enabled.
|
||||
file:line:error style messages enabled.
|
||||
@@ -17,8 +17,8 @@ Package hyphsubst Info: Redefined: \l@ngerman
|
||||
(hyphsubst) new value: 4 on input line 223.
|
||||
) (/usr/local/texlive/2018/texmf-dist/tex/latex/base/report.cls
|
||||
Document Class: report 2014/09/29 v1.4h Standard LaTeX document class
|
||||
(/usr/local/texlive/2018/texmf-dist/tex/latex/base/size11.clo
|
||||
File: size11.clo 2014/09/29 v1.4h Standard LaTeX file (size option)
|
||||
(/usr/local/texlive/2018/texmf-dist/tex/latex/base/size12.clo
|
||||
File: size12.clo 2014/09/29 v1.4h Standard LaTeX file (size option)
|
||||
)
|
||||
\c@part=\count80
|
||||
\c@chapter=\count81
|
||||
@@ -957,12 +957,12 @@ LaTeX Font Info: ... okay on input line 26.
|
||||
* \topmargin=-23.91173pt
|
||||
* \headheight=12.0pt
|
||||
* \headsep=25.0pt
|
||||
* \topskip=11.0pt
|
||||
* \topskip=12.0pt
|
||||
* \footskip=30.0pt
|
||||
* \marginparwidth=103.0pt
|
||||
* \marginparwidth=85.0pt
|
||||
* \marginparsep=10.0pt
|
||||
* \columnsep=10.0pt
|
||||
* \skip\footins=10.0pt plus 4.0pt minus 2.0pt
|
||||
* \skip\footins=10.8pt plus 4.0pt minus 2.0pt
|
||||
* \hoffset=0.0pt
|
||||
* \voffset=0.0pt
|
||||
* \mag=1000
|
||||
@@ -1033,7 +1033,7 @@ Package babel Info: Redefining german shorthand "~
|
||||
|
||||
|
||||
]
|
||||
Overfull \hbox (16.99998pt too wide) in paragraph at lines 48--57
|
||||
Overfull \hbox (17.99998pt too wide) in paragraph at lines 48--57
|
||||
[]|
|
||||
[]
|
||||
|
||||
@@ -1134,10 +1134,53 @@ Package babel Info: Redefining german shorthand "~
|
||||
[4
|
||||
|
||||
|
||||
]
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 52.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 52.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 52.
|
||||
(/Users/Esthi/thesis_ek/doc/bachelorarbeit_EstherKleinhenz/.texpadtmp/bachelorabeit_EstherKleinhenz.lof)
|
||||
\tf@lof=\write7
|
||||
\openout7 = `bachelorabeit_EstherKleinhenz.lof'.
|
||||
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 57.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 57.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 57.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 57.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 57.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 57.
|
||||
[1
|
||||
|
||||
|
||||
]
|
||||
\openout2 = `chapters/einleitung.aux'.
|
||||
|
||||
(./chapters/einleitung.tex
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 1.
|
||||
[2
|
||||
|
||||
|
||||
|
||||
]
|
||||
Kapitel 1.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 1.
|
||||
@@ -1146,73 +1189,69 @@ Package babel Info: Redefining german shorthand "|
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 5.
|
||||
(babel) in language on input line 6.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 5.
|
||||
(babel) in language on input line 6.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 5.
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
(babel) in language on input line 6.
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 10.
|
||||
(babel) in language on input line 11.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 10.
|
||||
(babel) in language on input line 11.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 10.
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
(babel) in language on input line 11.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 11.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 11.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 11.
|
||||
[3]
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 11.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 11.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 11.
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
)
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 55.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 55.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 55.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 55.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 55.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 55.
|
||||
[1
|
||||
|
||||
|
||||
|
||||
]
|
||||
|
||||
Package Fancyhdr Warning: \headheight is too small (12.0pt):
|
||||
Make it at least 13.59999pt.
|
||||
Make it at least 14.49998pt.
|
||||
We now make it that large for the rest of the document.
|
||||
This may cause the page layout to be inconsistent, however.
|
||||
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 55.
|
||||
(babel) in language on input line 57.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 55.
|
||||
(babel) in language on input line 57.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 55.
|
||||
(babel) in language on input line 57.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 55.
|
||||
(babel) in language on input line 57.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 55.
|
||||
(babel) in language on input line 57.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 55.
|
||||
[2]
|
||||
(babel) in language on input line 57.
|
||||
[4]
|
||||
\openout2 = `chapters/framework.aux'.
|
||||
|
||||
(./chapters/framework.tex
|
||||
@@ -1224,69 +1263,183 @@ Package babel Info: Redefining german shorthand "|
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 5.
|
||||
(babel) in language on input line 7.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 5.
|
||||
(babel) in language on input line 7.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 5.
|
||||
(babel) in language on input line 7.
|
||||
File: figures/MVP.png Graphic file (type bmp)
|
||||
<figures/MVP.png>
|
||||
|
||||
LaTeX Warning: `!h' float specifier changed to `!ht'.
|
||||
|
||||
LaTeX Font Info: Try loading font information for TS1+aer on input line 21.
|
||||
LaTeX Font Info: No file TS1aer.fd. on input line 21.
|
||||
|
||||
LaTeX Font Warning: Font shape `TS1/aer/m/n' undefined
|
||||
(Font) using `TS1/cmr/m/n' instead
|
||||
(Font) for symbol `textbullet' on input line 21.
|
||||
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 9.
|
||||
(babel) in language on input line 22.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 9.
|
||||
(babel) in language on input line 22.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 9.
|
||||
(babel) in language on input line 22.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 10.
|
||||
(babel) in language on input line 22.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 10.
|
||||
(babel) in language on input line 22.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 10.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 11.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 11.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 11.
|
||||
)
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 56.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 56.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 56.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 56.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 56.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 56.
|
||||
[3
|
||||
(babel) in language on input line 22.
|
||||
[5
|
||||
|
||||
|
||||
|
||||
|
||||
]
|
||||
File: figures/request-response-cycle.png Graphic file (type bmp)
|
||||
<figures/request-response-cycle.png>
|
||||
|
||||
|
||||
LaTeX Warning: `!h' float specifier changed to `!ht'.
|
||||
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 36.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 36.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 36.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 51.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 51.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 51.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 51.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 51.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 51.
|
||||
[6]
|
||||
Underfull \vbox (badness 10000) has occurred while \output is active []
|
||||
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 53.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 53.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 53.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 53.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 53.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 53.
|
||||
[7]
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 58.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 58.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 58.
|
||||
File: figures/virt-env-terminal.png Graphic file (type bmp)
|
||||
<figures/virt-env-terminal.png>
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 80.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 80.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 80.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 80.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 80.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 80.
|
||||
[8]
|
||||
File: figures/ldap-tree.png Graphic file (type bmp)
|
||||
<figures/ldap-tree.png>
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 95.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 95.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 95.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 97.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 97.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 97.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 97.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 97.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 97.
|
||||
[9]
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 118.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 118.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 118.
|
||||
|
||||
Underfull \vbox (badness 10000) has occurred while \output is active []
|
||||
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 120.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 120.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 120.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 120.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 120.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 120.
|
||||
[10]
|
||||
File: figures/bootstrap-head-tag.png Graphic file (type bmp)
|
||||
<figures/bootstrap-head-tag.png>
|
||||
File: figures/bootstrap-class-example.png Graphic file (type bmp)
|
||||
<figures/bootstrap-class-example.png>
|
||||
|
||||
|
||||
LaTeX Warning: `!h' float specifier changed to `!ht'.
|
||||
|
||||
)
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 58.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 58.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 58.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 58.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 58.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 58.
|
||||
[11]
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 58.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 58.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 58.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 58.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 58.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 58.
|
||||
[12]
|
||||
\openout2 = `chapters/prototyp.aux'.
|
||||
|
||||
(./chapters/prototyp.tex
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 1.
|
||||
[4
|
||||
|
||||
|
||||
|
||||
|
||||
]
|
||||
Kapitel 3.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 1.
|
||||
@@ -1295,35 +1448,16 @@ Package babel Info: Redefining german shorthand "|
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 3.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 3.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 3.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 4.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 4.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 4.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 5.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 5.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 5.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 6.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 6.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 6.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 7.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 7.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 7.
|
||||
|
||||
Overfull \hbox (6.80373pt too wide) in paragraph at lines 6--7
|
||||
\T1/aer/m/n/12 Grundlegender Auf-bau der Web-site, Ver-wal-tung der Da-ten evlt auf noch-mal Taggable-
|
||||
[]
|
||||
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 8.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
@@ -1331,46 +1465,75 @@ Package babel Info: Redefining german shorthand "|
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 8.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 9.
|
||||
(babel) in language on input line 11.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 9.
|
||||
(babel) in language on input line 11.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 9.
|
||||
(babel) in language on input line 11.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 15.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 15.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 15.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 18.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 18.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 18.
|
||||
|
||||
Overfull \hbox (1.12642pt too wide) in paragraph at lines 19--20
|
||||
\T1/aer/m/n/12 Tags als ein-ge-logg-ter User abon-nie-ren und ver-wal-ten Front-end und Admin-Backend?
|
||||
[]
|
||||
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 21.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 21.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 21.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 24.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 24.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 24.
|
||||
)
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 57.
|
||||
(babel) in language on input line 59.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 57.
|
||||
(babel) in language on input line 59.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 57.
|
||||
(babel) in language on input line 59.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 57.
|
||||
(babel) in language on input line 59.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 57.
|
||||
(babel) in language on input line 59.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 57.
|
||||
[5]
|
||||
\openout2 = `chapters/ergebnis.aux'.
|
||||
|
||||
(./chapters/ergebnis.tex
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 1.
|
||||
[6
|
||||
(babel) in language on input line 59.
|
||||
[13
|
||||
|
||||
|
||||
|
||||
|
||||
]
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 59.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 59.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 59.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 59.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 59.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 59.
|
||||
[14]
|
||||
\openout2 = `chapters/ergebnis.aux'.
|
||||
|
||||
(./chapters/ergebnis.tex
|
||||
Kapitel 4.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 1.
|
||||
@@ -1390,18 +1553,23 @@ Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 3.
|
||||
)
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 58.
|
||||
(babel) in language on input line 60.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 58.
|
||||
(babel) in language on input line 60.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 58.
|
||||
(babel) in language on input line 60.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 58.
|
||||
(babel) in language on input line 60.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 58.
|
||||
(babel) in language on input line 60.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 58.
|
||||
[7]
|
||||
(babel) in language on input line 60.
|
||||
[15
|
||||
|
||||
|
||||
|
||||
|
||||
]
|
||||
\openout2 = `chapters/ausblick.aux'.
|
||||
|
||||
(./chapters/ausblick.tex)
|
||||
@@ -1420,7 +1588,7 @@ Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 1.
|
||||
[8
|
||||
[16
|
||||
|
||||
|
||||
|
||||
@@ -1437,18 +1605,18 @@ Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 1.
|
||||
)
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 60.
|
||||
(babel) in language on input line 62.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 60.
|
||||
(babel) in language on input line 62.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 60.
|
||||
(babel) in language on input line 62.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 60.
|
||||
(babel) in language on input line 62.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 60.
|
||||
(babel) in language on input line 62.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 60.
|
||||
[9] (/Users/Esthi/thesis_ek/doc/bachelorarbeit_EstherKleinhenz/.texpadtmp/bachelorabeit_EstherKleinhenz.bbl
|
||||
(babel) in language on input line 62.
|
||||
[17] (/Users/Esthi/thesis_ek/doc/bachelorarbeit_EstherKleinhenz/.texpadtmp/bachelorabeit_EstherKleinhenz.bbl
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
@@ -1461,7 +1629,7 @@ Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 1.
|
||||
[10
|
||||
[18
|
||||
|
||||
|
||||
|
||||
@@ -1472,61 +1640,76 @@ Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 1.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 1.
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ̈ in font aer10!
|
||||
Missing character: There is no ’ in font aer10!
|
||||
|
||||
Underfull \hbox (badness 10000) in paragraph at lines 12--18
|
||||
\T1/aer/m/n/10.95 nnennandukwe-python-is-the-back-end-programming-language-of-the-future-
|
||||
Underfull \hbox (badness 10000) in paragraph at lines 4--9
|
||||
\T1/aer/m/n/12 https://www.datacamp.com/community/tutorials/pep8-tutorial-python-
|
||||
[]
|
||||
|
||||
Missing character: There is no ’ in font aer12!
|
||||
|
||||
Underfull \hbox (badness 1521) in paragraph at lines 31--36
|
||||
[]\T1/aer/m/n/12 Adam King. Djan-go midd-le-wa-res and the re-quest/-re-spon-se cy-cle.
|
||||
[]
|
||||
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ̈ in font aer12!
|
||||
Missing character: There is no ’ in font aer12!
|
||||
|
||||
Underfull \hbox (badness 10000) in paragraph at lines 46--52
|
||||
\T1/aer/m/n/12 medium-com-nnennandukwe-python-is-the-back-end-programming-
|
||||
[]
|
||||
|
||||
|
||||
Underfull \hbox (badness 10000) in paragraph at lines 20--26
|
||||
[]\T1/aer/m/n/10.95 Alexy She-lest. Mo-del view con-trol-ler, mo-del view pre-
|
||||
Underfull \hbox (badness 10000) in paragraph at lines 54--60
|
||||
[]\T1/aer/m/n/12 Alexy She-lest. Mo-del view con-trol-ler, mo-del view pre-
|
||||
[]
|
||||
|
||||
|
||||
Underfull \hbox (badness 10000) in paragraph at lines 20--26
|
||||
\T1/aer/m/n/10.95 sen-ter, and mo-del view view-mo-del de-sign pat-terns. 2009.
|
||||
Underfull \hbox (badness 10000) in paragraph at lines 54--60
|
||||
\T1/aer/m/n/12 sen-ter, and mo-del view view-mo-del de-sign pat-terns. 2009.
|
||||
[]
|
||||
|
||||
|
||||
Underfull \hbox (badness 10000) in paragraph at lines 20--26
|
||||
\T1/aer/m/n/10.95 https://www.codeproject.com/Articles/42830/Model-View-Controller-Model-
|
||||
Underfull \hbox (badness 10000) in paragraph at lines 54--60
|
||||
\T1/aer/m/n/12 https://www.codeproject.com/Articles/42830/Model-View-Controller-
|
||||
[]
|
||||
|
||||
)
|
||||
Package atveryend Info: Empty hook `BeforeClearDocument' on input line 75.
|
||||
Package atveryend Info: Empty hook `BeforeClearDocument' on input line 77.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 75.
|
||||
(babel) in language on input line 77.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 75.
|
||||
(babel) in language on input line 77.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 75.
|
||||
(babel) in language on input line 77.
|
||||
Package babel Info: Redefining german shorthand "f
|
||||
(babel) in language on input line 75.
|
||||
(babel) in language on input line 77.
|
||||
Package babel Info: Redefining german shorthand "|
|
||||
(babel) in language on input line 75.
|
||||
(babel) in language on input line 77.
|
||||
Package babel Info: Redefining german shorthand "~
|
||||
(babel) in language on input line 75.
|
||||
[11]
|
||||
Package atveryend Info: Empty hook `AfterLastShipout' on input line 75.
|
||||
(babel) in language on input line 77.
|
||||
[19]
|
||||
Package atveryend Info: Empty hook `AfterLastShipout' on input line 77.
|
||||
(/Users/Esthi/thesis_ek/doc/bachelorarbeit_EstherKleinhenz/.texpadtmp/bachelorabeit_EstherKleinhenz.aux (/Users/Esthi/thesis_ek/doc/bachelorarbeit_EstherKleinhenz/.texpadtmp/titlepage/titlepage.aux) (/Users/Esthi/thesis_ek/doc/bachelorarbeit_EstherKleinhenz/.texpadtmp/abstract/abstract.aux) (/Users/Esthi/thesis_ek/doc/bachelorarbeit_EstherKleinhenz/.texpadtmp/chapters/einleitung.aux) (/Users/Esthi/thesis_ek/doc/bachelorarbeit_EstherKleinhenz/.texpadtmp/chapters/framework.aux) (/Users/Esthi/thesis_ek/doc/bachelorarbeit_EstherKleinhenz/.texpadtmp/chapters/prototyp.aux) (/Users/Esthi/thesis_ek/doc/bachelorarbeit_EstherKleinhenz/.texpadtmp/chapters/ergebnis.aux) (/Users/Esthi/thesis_ek/doc/bachelorarbeit_EstherKleinhenz/.texpadtmp/chapters/ausblick.aux) (/Users/Esthi/thesis_ek/doc/bachelorarbeit_EstherKleinhenz/.texpadtmp/chapters/fazit.aux))
|
||||
Package atveryend Info: Empty hook `AtVeryEndDocument' on input line 75.
|
||||
Package atveryend Info: Executing hook `AtEndAfterFileList' on input line 75.
|
||||
Package atveryend Info: Empty hook `AtVeryEndDocument' on input line 77.
|
||||
Package atveryend Info: Executing hook `AtEndAfterFileList' on input line 77.
|
||||
Package rerunfilecheck Info: File `bachelorabeit_EstherKleinhenz.out' has not changed.
|
||||
(rerunfilecheck) Checksum: 1C7F7EA8FD90A663BA0DCEA09291597A.
|
||||
Package atveryend Info: Empty hook `AtVeryVeryEnd' on input line 75.
|
||||
|
||||
|
||||
LaTeX Font Warning: Some font shapes were not available, defaults substituted.
|
||||
|
||||
Package atveryend Info: Empty hook `AtVeryVeryEnd' on input line 77.
|
||||
)
|
||||
(\end occurred when \ifnum on line 5 was incomplete)
|
||||
Here is how much of TeX's memory you used:
|
||||
26504 strings out of 492970
|
||||
475230 string characters out of 6133939
|
||||
545186 words of memory out of 5000000
|
||||
30130 multiletter control sequences out of 15000+600000
|
||||
553864 words of font info for 60 fonts, out of 8000000 for 9000
|
||||
26561 strings out of 492970
|
||||
476474 string characters out of 6133939
|
||||
547394 words of memory out of 5000000
|
||||
30175 multiletter control sequences out of 15000+600000
|
||||
554220 words of font info for 61 fonts, out of 8000000 for 9000
|
||||
1348 hyphenation exceptions out of 8191
|
||||
58i,11n,50p,10437b,822s stack positions out of 5000i,500n,10000p,200000b,80000s
|
||||
58i,11n,50p,10437b,892s stack positions out of 5000i,500n,10000p,200000b,80000s
|
||||
|
||||
Output written on /Users/Esthi/thesis_ek/doc/bachelorarbeit_EstherKleinhenz/.texpadtmp/bachelorabeit_EstherKleinhenz.pdf (17 pages).
|
||||
Output written on /Users/Esthi/thesis_ek/doc/bachelorarbeit_EstherKleinhenz/.texpadtmp/bachelorabeit_EstherKleinhenz.pdf (25 pages).
|
||||
@@ -1,21 +1,23 @@
|
||||
\BOOKMARK [0][-]{figure.caption.1}{Abstract}{}% 1
|
||||
\BOOKMARK [0][-]{chapter.1}{Einleitung}{}% 2
|
||||
\BOOKMARK [1][-]{section.1.1}{Ausgangssituation}{chapter.1}% 3
|
||||
\BOOKMARK [1][-]{section.1.2}{Ziel\040der\040Arbeit}{chapter.1}% 4
|
||||
\BOOKMARK [0][-]{chapter.2}{Framework}{}% 5
|
||||
\BOOKMARK [1][-]{section.2.1}{Django}{chapter.2}% 6
|
||||
\BOOKMARK [1][-]{section.2.2}{Erweiterung}{chapter.2}% 7
|
||||
\BOOKMARK [2][-]{subsection.2.2.1}{Taggable-Manager}{section.2.2}% 8
|
||||
\BOOKMARK [1][-]{section.2.3}{Bootstrap}{chapter.2}% 9
|
||||
\BOOKMARK [0][-]{chapter.3}{Prototyp}{}% 10
|
||||
\BOOKMARK [1][-]{section.3.1}{Organisation}{chapter.3}% 11
|
||||
\BOOKMARK [2][-]{subsection.3.1.1}{Verwaltung\040im\040Administrator-Backend}{section.3.1}% 12
|
||||
\BOOKMARK [2][-]{subsection.3.1.2}{Berechtigung\040der\040User}{section.3.1}% 13
|
||||
\BOOKMARK [1][-]{section.3.2}{Funktion}{chapter.3}% 14
|
||||
\BOOKMARK [2][-]{subsection.3.2.1}{Abonnieren}{section.3.2}% 15
|
||||
\BOOKMARK [2][-]{subsection.3.2.2}{Filtern}{section.3.2}% 16
|
||||
\BOOKMARK [2][-]{subsection.3.2.3}{Benachrichtigung}{section.3.2}% 17
|
||||
\BOOKMARK [0][-]{chapter.4}{Ergebnis}{}% 18
|
||||
\BOOKMARK [1][-]{subsection.4.0.1}{Evaluierung}{chapter.4}% 19
|
||||
\BOOKMARK [0][-]{chapter.5}{Zusammenfassung\040und\040Ausblick}{}% 20
|
||||
\BOOKMARK [0][-]{chapter*.4}{Referenzen}{}% 21
|
||||
\BOOKMARK [0][-]{chapter*.4}{Abbildungsverzeichnis}{}% 2
|
||||
\BOOKMARK [0][-]{chapter.1}{Einleitung}{}% 3
|
||||
\BOOKMARK [1][-]{section.1.1}{Ausgangssituation}{chapter.1}% 4
|
||||
\BOOKMARK [1][-]{section.1.2}{Ziel\040der\040Arbeit}{chapter.1}% 5
|
||||
\BOOKMARK [0][-]{chapter.2}{Framework}{}% 6
|
||||
\BOOKMARK [1][-]{section.2.1}{Django}{chapter.2}% 7
|
||||
\BOOKMARK [2][-]{subsection.2.1.1}{Besonderheiten}{section.2.1}% 8
|
||||
\BOOKMARK [1][-]{section.2.2}{Erweiterungen}{chapter.2}% 9
|
||||
\BOOKMARK [2][-]{subsection.2.2.1}{Taggable-Manager}{section.2.2}% 10
|
||||
\BOOKMARK [1][-]{section.2.3}{Bootstrap}{chapter.2}% 11
|
||||
\BOOKMARK [0][-]{chapter.3}{Prototyp}{}% 12
|
||||
\BOOKMARK [1][-]{section.3.1}{Organisation}{chapter.3}% 13
|
||||
\BOOKMARK [2][-]{subsection.3.1.1}{Verwaltung\040im\040Administrator-Backend}{section.3.1}% 14
|
||||
\BOOKMARK [2][-]{subsection.3.1.2}{Berechtigung\040der\040User}{section.3.1}% 15
|
||||
\BOOKMARK [1][-]{section.3.2}{Funktion}{chapter.3}% 16
|
||||
\BOOKMARK [2][-]{subsection.3.2.1}{Abonnieren}{section.3.2}% 17
|
||||
\BOOKMARK [2][-]{subsection.3.2.2}{Filtern}{section.3.2}% 18
|
||||
\BOOKMARK [2][-]{subsection.3.2.3}{Benachrichtigung}{section.3.2}% 19
|
||||
\BOOKMARK [0][-]{chapter.4}{Ergebnis}{}% 20
|
||||
\BOOKMARK [1][-]{subsection.4.0.1}{Evaluierung}{chapter.4}% 21
|
||||
\BOOKMARK [0][-]{chapter.5}{Zusammenfassung\040und\040Ausblick}{}% 22
|
||||
\BOOKMARK [0][-]{chapter*.11}{Referenzen}{}% 23
|
||||
BIN
Binary file not shown.
@@ -1,23 +1,25 @@
|
||||
\babel@toc {german}{}
|
||||
\babel@toc {german}{}
|
||||
\contentsline {chapter}{Abstract}{i}{figure.caption.1}
|
||||
\contentsline {chapter}{\numberline {1}Einleitung}{1}{chapter.1}
|
||||
\contentsline {section}{\numberline {1.1}Ausgangssituation}{1}{section.1.1}
|
||||
\contentsline {section}{\numberline {1.2}Ziel der Arbeit}{1}{section.1.2}
|
||||
\contentsline {chapter}{\numberline {2}Framework}{3}{chapter.2}
|
||||
\contentsline {section}{\numberline {2.1}Django}{3}{section.2.1}
|
||||
\contentsline {section}{\numberline {2.2}Erweiterung}{3}{section.2.2}
|
||||
\contentsline {subsection}{\numberline {2.2.1}Taggable-Manager}{3}{subsection.2.2.1}
|
||||
\contentsline {section}{\numberline {2.3}Bootstrap}{3}{section.2.3}
|
||||
\contentsline {chapter}{\numberline {3}Prototyp}{5}{chapter.3}
|
||||
\contentsline {section}{\numberline {3.1}Organisation}{5}{section.3.1}
|
||||
\contentsline {subsection}{\numberline {3.1.1}Verwaltung im Administrator-Backend}{5}{subsection.3.1.1}
|
||||
\contentsline {subsection}{\numberline {3.1.2}Berechtigung der User}{5}{subsection.3.1.2}
|
||||
\contentsline {section}{\numberline {3.2}Funktion}{5}{section.3.2}
|
||||
\contentsline {subsection}{\numberline {3.2.1}Abonnieren}{5}{subsection.3.2.1}
|
||||
\contentsline {subsection}{\numberline {3.2.2}Filtern}{5}{subsection.3.2.2}
|
||||
\contentsline {subsection}{\numberline {3.2.3}Benachrichtigung}{5}{subsection.3.2.3}
|
||||
\contentsline {chapter}{\numberline {4}Ergebnis}{7}{chapter.4}
|
||||
\contentsline {subsection}{\numberline {4.0.1}Evaluierung}{7}{subsection.4.0.1}
|
||||
\contentsline {chapter}{\numberline {5}Zusammenfassung und Ausblick}{9}{chapter.5}
|
||||
\contentsline {chapter}{Referenzen}{11}{chapter*.4}
|
||||
\contentsline {chapter}{Abbildungsverzeichnis}{1}{chapter*.4}
|
||||
\contentsline {chapter}{\numberline {1}Einleitung}{3}{chapter.1}
|
||||
\contentsline {section}{\numberline {1.1}Ausgangssituation}{3}{section.1.1}
|
||||
\contentsline {section}{\numberline {1.2}Ziel der Arbeit}{4}{section.1.2}
|
||||
\contentsline {chapter}{\numberline {2}Framework}{5}{chapter.2}
|
||||
\contentsline {section}{\numberline {2.1}Django}{5}{section.2.1}
|
||||
\contentsline {subsection}{\numberline {2.1.1}Besonderheiten}{6}{subsection.2.1.1}
|
||||
\contentsline {section}{\numberline {2.2}Erweiterungen}{8}{section.2.2}
|
||||
\contentsline {subsection}{\numberline {2.2.1}Taggable-Manager}{10}{subsection.2.2.1}
|
||||
\contentsline {section}{\numberline {2.3}Bootstrap}{11}{section.2.3}
|
||||
\contentsline {chapter}{\numberline {3}Prototyp}{13}{chapter.3}
|
||||
\contentsline {section}{\numberline {3.1}Organisation}{13}{section.3.1}
|
||||
\contentsline {subsection}{\numberline {3.1.1}Verwaltung im Administrator-Backend}{13}{subsection.3.1.1}
|
||||
\contentsline {subsection}{\numberline {3.1.2}Berechtigung der User}{13}{subsection.3.1.2}
|
||||
\contentsline {section}{\numberline {3.2}Funktion}{13}{section.3.2}
|
||||
\contentsline {subsection}{\numberline {3.2.1}Abonnieren}{13}{subsection.3.2.1}
|
||||
\contentsline {subsection}{\numberline {3.2.2}Filtern}{13}{subsection.3.2.2}
|
||||
\contentsline {subsection}{\numberline {3.2.3}Benachrichtigung}{14}{subsection.3.2.3}
|
||||
\contentsline {chapter}{\numberline {4}Ergebnis}{15}{chapter.4}
|
||||
\contentsline {subsection}{\numberline {4.0.1}Evaluierung}{15}{subsection.4.0.1}
|
||||
\contentsline {chapter}{\numberline {5}Zusammenfassung und Ausblick}{17}{chapter.5}
|
||||
\contentsline {chapter}{Referenzen}{19}{chapter*.11}
|
||||
@@ -1,7 +1,7 @@
|
||||
\relax
|
||||
\providecommand\hyper@newdestlabel[2]{}
|
||||
\@setckpt{chapters/ausblick}{
|
||||
\setcounter{page}{8}
|
||||
\setcounter{page}{16}
|
||||
\setcounter{equation}{0}
|
||||
\setcounter{enumi}{0}
|
||||
\setcounter{enumii}{0}
|
||||
@@ -28,7 +28,7 @@
|
||||
\setcounter{Item}{0}
|
||||
\setcounter{Hfootnote}{0}
|
||||
\setcounter{Hy@AnnotLevel}{0}
|
||||
\setcounter{bookmark@seq@number}{19}
|
||||
\setcounter{bookmark@seq@number}{21}
|
||||
\setcounter{NAT@ctr}{0}
|
||||
\setcounter{lstlisting}{0}
|
||||
\setcounter{section@level}{0}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
\relax
|
||||
\providecommand\hyper@newdestlabel[2]{}
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {1}Einleitung}{1}{chapter.1}}
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {1}Einleitung}{3}{chapter.1}}
|
||||
\@writefile{lof}{\addvspace {10\p@ }}
|
||||
\@writefile{lot}{\addvspace {10\p@ }}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {1.1}Ausgangssituation}{1}{section.1.1}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {1.2}Ziel der Arbeit}{1}{section.1.2}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {1.1}Ausgangssituation}{3}{section.1.1}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {1.2}Ziel der Arbeit}{4}{section.1.2}}
|
||||
\@setckpt{chapters/einleitung}{
|
||||
\setcounter{page}{3}
|
||||
\setcounter{page}{5}
|
||||
\setcounter{equation}{0}
|
||||
\setcounter{enumi}{0}
|
||||
\setcounter{enumii}{0}
|
||||
@@ -33,7 +33,7 @@
|
||||
\setcounter{Item}{0}
|
||||
\setcounter{Hfootnote}{0}
|
||||
\setcounter{Hy@AnnotLevel}{0}
|
||||
\setcounter{bookmark@seq@number}{4}
|
||||
\setcounter{bookmark@seq@number}{5}
|
||||
\setcounter{NAT@ctr}{0}
|
||||
\setcounter{lstlisting}{0}
|
||||
\setcounter{section@level}{0}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
\relax
|
||||
\providecommand\hyper@newdestlabel[2]{}
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {4}Ergebnis}{7}{chapter.4}}
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {4}Ergebnis}{15}{chapter.4}}
|
||||
\@writefile{lof}{\addvspace {10\p@ }}
|
||||
\@writefile{lot}{\addvspace {10\p@ }}
|
||||
\newlabel{ch:ergebnis}{{4}{7}{Ergebnis}{chapter.4}{}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.0.1}Evaluierung}{7}{subsection.4.0.1}}
|
||||
\newlabel{ch:ergebnis}{{4}{15}{Ergebnis}{chapter.4}{}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.0.1}Evaluierung}{15}{subsection.4.0.1}}
|
||||
\@setckpt{chapters/ergebnis}{
|
||||
\setcounter{page}{8}
|
||||
\setcounter{page}{16}
|
||||
\setcounter{equation}{0}
|
||||
\setcounter{enumi}{0}
|
||||
\setcounter{enumii}{0}
|
||||
@@ -33,7 +33,7 @@
|
||||
\setcounter{Item}{0}
|
||||
\setcounter{Hfootnote}{0}
|
||||
\setcounter{Hy@AnnotLevel}{0}
|
||||
\setcounter{bookmark@seq@number}{19}
|
||||
\setcounter{bookmark@seq@number}{21}
|
||||
\setcounter{NAT@ctr}{0}
|
||||
\setcounter{lstlisting}{0}
|
||||
\setcounter{section@level}{0}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
\relax
|
||||
\providecommand\hyper@newdestlabel[2]{}
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {5}Zusammenfassung und Ausblick}{9}{chapter.5}}
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {5}Zusammenfassung und Ausblick}{17}{chapter.5}}
|
||||
\@writefile{lof}{\addvspace {10\p@ }}
|
||||
\@writefile{lot}{\addvspace {10\p@ }}
|
||||
\newlabel{ch:zusammenfassung}{{5}{9}{Zusammenfassung und Ausblick}{chapter.5}{}}
|
||||
\newlabel{ch:zusammenfassung}{{5}{17}{Zusammenfassung und Ausblick}{chapter.5}{}}
|
||||
\@setckpt{chapters/fazit}{
|
||||
\setcounter{page}{10}
|
||||
\setcounter{page}{18}
|
||||
\setcounter{equation}{0}
|
||||
\setcounter{enumi}{0}
|
||||
\setcounter{enumii}{0}
|
||||
@@ -32,7 +32,7 @@
|
||||
\setcounter{Item}{0}
|
||||
\setcounter{Hfootnote}{0}
|
||||
\setcounter{Hy@AnnotLevel}{0}
|
||||
\setcounter{bookmark@seq@number}{20}
|
||||
\setcounter{bookmark@seq@number}{22}
|
||||
\setcounter{NAT@ctr}{0}
|
||||
\setcounter{lstlisting}{0}
|
||||
\setcounter{section@level}{0}
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
\relax
|
||||
\providecommand\hyper@newdestlabel[2]{}
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {2}Framework}{3}{chapter.2}}
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {2}Framework}{5}{chapter.2}}
|
||||
\@writefile{lof}{\addvspace {10\p@ }}
|
||||
\@writefile{lot}{\addvspace {10\p@ }}
|
||||
\newlabel{ch:framework}{{2}{3}{Framework}{chapter.2}{}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {2.1}Django}{3}{section.2.1}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {2.2}Erweiterung}{3}{section.2.2}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {2.2.1}Taggable-Manager}{3}{subsection.2.2.1}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {2.3}Bootstrap}{3}{section.2.3}}
|
||||
\newlabel{ch:framework}{{2}{5}{Framework}{chapter.2}{}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {2.1}Django}{5}{section.2.1}}
|
||||
\@writefile{lof}{\contentsline {figure}{\numberline {2.1}{\ignorespaces Vereinfachter MVP\relax }}{6}{figure.caption.5}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {2.1.1}Besonderheiten}{6}{subsection.2.1.1}}
|
||||
\@writefile{lof}{\contentsline {figure}{\numberline {2.2}{\ignorespaces Request-Response-Kreislauf des Django Frameworks\relax }}{7}{figure.caption.6}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {2.2}Erweiterungen}{8}{section.2.2}}
|
||||
\@writefile{lof}{\contentsline {figure}{\numberline {2.3}{\ignorespaces Erstellen der virtuelle Umgebung im Terminal\relax }}{8}{figure.caption.7}}
|
||||
\@writefile{lof}{\contentsline {figure}{\numberline {2.4}{\ignorespaces Beispiel eines LDAP-Trees\relax }}{9}{figure.caption.8}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {2.2.1}Taggable-Manager}{10}{subsection.2.2.1}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {2.3}Bootstrap}{11}{section.2.3}}
|
||||
\@writefile{lof}{\contentsline {figure}{\numberline {2.5}{\ignorespaces Einbindung von Bootstrap in einer HTML-Datei\relax }}{11}{figure.caption.9}}
|
||||
\@writefile{lof}{\contentsline {figure}{\numberline {2.6}{\ignorespaces Bootstrap-Klassen in HTML-Tag\relax }}{12}{figure.caption.10}}
|
||||
\@setckpt{chapters/framework}{
|
||||
\setcounter{page}{4}
|
||||
\setcounter{page}{13}
|
||||
\setcounter{equation}{0}
|
||||
\setcounter{enumi}{0}
|
||||
\setcounter{enumii}{0}
|
||||
@@ -24,7 +31,7 @@
|
||||
\setcounter{subsubsection}{0}
|
||||
\setcounter{paragraph}{0}
|
||||
\setcounter{subparagraph}{0}
|
||||
\setcounter{figure}{0}
|
||||
\setcounter{figure}{6}
|
||||
\setcounter{table}{0}
|
||||
\setcounter{float@type}{8}
|
||||
\setcounter{parentequation}{0}
|
||||
@@ -36,7 +43,7 @@
|
||||
\setcounter{Item}{0}
|
||||
\setcounter{Hfootnote}{0}
|
||||
\setcounter{Hy@AnnotLevel}{0}
|
||||
\setcounter{bookmark@seq@number}{9}
|
||||
\setcounter{bookmark@seq@number}{11}
|
||||
\setcounter{NAT@ctr}{0}
|
||||
\setcounter{lstlisting}{0}
|
||||
\setcounter{section@level}{0}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
\relax
|
||||
\providecommand\hyper@newdestlabel[2]{}
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {3}Prototyp}{5}{chapter.3}}
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {3}Prototyp}{13}{chapter.3}}
|
||||
\@writefile{lof}{\addvspace {10\p@ }}
|
||||
\@writefile{lot}{\addvspace {10\p@ }}
|
||||
\newlabel{ch:prototyp}{{3}{5}{Prototyp}{chapter.3}{}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {3.1}Organisation}{5}{section.3.1}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.1.1}Verwaltung im Administrator-Backend}{5}{subsection.3.1.1}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.1.2}Berechtigung der User}{5}{subsection.3.1.2}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {3.2}Funktion}{5}{section.3.2}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.1}Abonnieren}{5}{subsection.3.2.1}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.2}Filtern}{5}{subsection.3.2.2}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.3}Benachrichtigung}{5}{subsection.3.2.3}}
|
||||
\newlabel{ch:prototyp}{{3}{13}{Prototyp}{chapter.3}{}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {3.1}Organisation}{13}{section.3.1}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.1.1}Verwaltung im Administrator-Backend}{13}{subsection.3.1.1}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.1.2}Berechtigung der User}{13}{subsection.3.1.2}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {3.2}Funktion}{13}{section.3.2}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.1}Abonnieren}{13}{subsection.3.2.1}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.2}Filtern}{13}{subsection.3.2.2}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.3}Benachrichtigung}{14}{subsection.3.2.3}}
|
||||
\@setckpt{chapters/prototyp}{
|
||||
\setcounter{page}{6}
|
||||
\setcounter{page}{15}
|
||||
\setcounter{equation}{0}
|
||||
\setcounter{enumi}{0}
|
||||
\setcounter{enumii}{0}
|
||||
@@ -39,7 +39,7 @@
|
||||
\setcounter{Item}{0}
|
||||
\setcounter{Hfootnote}{0}
|
||||
\setcounter{Hy@AnnotLevel}{0}
|
||||
\setcounter{bookmark@seq@number}{17}
|
||||
\setcounter{bookmark@seq@number}{19}
|
||||
\setcounter{NAT@ctr}{0}
|
||||
\setcounter{lstlisting}{0}
|
||||
\setcounter{section@level}{0}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
\relax
|
||||
\@setckpt{preambule/thesis.preamble.tex}{
|
||||
\setcounter{page}{1}
|
||||
\setcounter{equation}{0}
|
||||
\setcounter{enumi}{0}
|
||||
\setcounter{enumii}{0}
|
||||
\setcounter{enumiii}{0}
|
||||
\setcounter{enumiv}{0}
|
||||
\setcounter{footnote}{0}
|
||||
\setcounter{mpfootnote}{0}
|
||||
\setcounter{part}{0}
|
||||
\setcounter{chapter}{0}
|
||||
\setcounter{section}{0}
|
||||
\setcounter{subsection}{0}
|
||||
\setcounter{subsubsection}{0}
|
||||
\setcounter{paragraph}{0}
|
||||
\setcounter{subparagraph}{0}
|
||||
\setcounter{figure}{0}
|
||||
\setcounter{table}{0}
|
||||
}
|
||||
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
\RequirePackage[ngerman=ngerman-x-latest]{hyphsubst}
|
||||
\documentclass[11pt,a4paper,openright,twoside]{report}
|
||||
\documentclass[12pt,a4paper,openright,twoside]{report}
|
||||
%------------------------------------------------------------------------------
|
||||
% preambule
|
||||
\include{preambule/thesis.preamble}
|
||||
@@ -49,6 +49,8 @@
|
||||
\tableofcontents
|
||||
\cleardoublepage
|
||||
\vspace{3cm}
|
||||
\listoffigures
|
||||
\vspace{3cm}
|
||||
%------------------------------------------------------------------------------
|
||||
%body of thesis comes here
|
||||
\pagenumbering{arabic}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
\chapter{Einleitung}
|
||||
\textcolor{red}{Die vorliegende Arbeit beschäftigt sich mit der wachsenden E-Mail-Flut in den Postfächern der Studierenden und wie man diese reduzieren kann.}
|
||||
Schon seit geraumer Zeit ist bekannt, dass das Versenden von Informationen über elektronische Post nicht nur Vorteile mit sich bringt. Wie der Spezialist für Gesundheitsprozesseratung in einem Bericht der Mitteldeutschen Zeitung erwähnt, "macht es die stets wachsende E-Mail-Menge unmöglich sich vernünftig mit den Informationen zu befassen"([Ver13]). Nicht nur am Arbeitsplatz sondern auch in Hochschulen wird Gebrauch gemacht, weitere Empfänger oder sogar ganze Verteiler mit in die Kopie einer E-Mail zu integrieren. Um die Prioritäten der Informationen besser bilden zu können, sollen Studierende selbst entscheiden, welche Nachrichten relevant sind. Hierfür wird eine Social Media Plattform mit personalisierbarem Dashboard implementiert.
|
||||
|
||||
Schon seit geraumer Zeit ist bekannt, dass das Versenden von Informationen über elektronische Post nicht nur Vorteile mit sich bringt. Wie der Spezialist für Gesundheitsprozessberatung in einem Bericht der Mitteldeutschen Zeitung erwähnt, \glqq macht es die stets wachsende E-Mail-Menge unmöglich sich vernünftig mit den Informationen zu befassen"([Ver13]). Nicht nur am Arbeitsplatz sondern auch in Hochschulen wird Gebrauch gemacht, weitere Empfänger oder sogar ganze Verteiler mit in die Kopie einer E-Mail zu integrieren. Um die Prioritäten der Informationen besser bilden zu können, sollen Studierende selbst entscheiden, welche Nachrichten relevant sind. Hierfür wird eine Social Media Plattform mit personalisierbarem Dashboard implementiert.
|
||||
|
||||
\section{Ausgangssituation}
|
||||
Alle Informationen der Fakultät Elektrotechnik Feinwerktechnik Informationstechnik, kurz efi, werden über die globalen Verteiler des Hochschulinternen Postfaches versendet. Viele dieser Daten sind jedoch nur für eine geringe Schnittmenge der Empfänger relevant und lassen sich nur schwer priorisieren. Das ständig überlastete Postfach muss somit regelmä"sig gepflegt werden. Einen massiven Administrativen Aufwand bedeutet es, E-Mails zu filtern und nach persönlichem Ermessen zu verwalten.
|
||||
Zudem leidet die Nachhaltigkeit der Informationen. Möchten die Empfänger ältere E-Mails abrufen, mussten diese meist schon entfernt werden um Platz für den neuen, eintreffenden E-Mail-Verkehr zu schaffen.
|
||||
Diese Situation führt dazu, dass Empfänger die Informationen meist nicht lesen und sofort entfernen. Die Ersteller dieser haben keinerlei Möglichkeiten zu überprüfen ob und wie viele Studierende und Dozenten eingehende Nachrichten öffnen und lesen.
|
||||
Diese Situation führt dazu, dass Empfänger die Informationen meist nicht lesen und sofort entfernen. Die Ersteller haben keinerlei Möglichkeiten zu überprüfen ob und wie viele Studierende und Dozenten eingehende Nachrichten öffnen und lesen.
|
||||
|
||||
\section{Ziel der Arbeit}
|
||||
Ziel der Arbeit ist es, durch die Einbindung einer Social Media Plattform den Speicheraufwand des Hochschulpostfaches für Studierende der Efi-Fakultät zu reduzieren. Die Flut an E-Mails soll durch das Verwenden eines personalisierte Dashboard gedrosselt werden. Hierbei wird zunächst der Fokus auf die grundlegenden Funktionen der Website wert gelegt.
|
||||
Zudem sollen die Verfasser der Informationen benachrichtigt werden, in welchem Umfang die hochgeladenen Informationen bereits abonniert und gelesen wurden.
|
||||
Ziel der Arbeit ist es, durch die Einbindung einer Social Media Plattform den Speicheraufwand des Hochschulpostfaches für Studierende der Efi-Fakultät zu reduzieren. Die Flut an E-Mails soll durch das Verwenden eines personalisierte Dashboard gedrosselt werden. Hierbei wird zunächst der Fokus auf die grundlegenden Funktionen der Website gelegt. Dazu gehört das Abonnieren, einpflegen von neuen und löschen von alten Nachrichten.
|
||||
Zudem sollen die Autoren benachrichtigt werden, in welchem Umfang die hochgeladenen Informationen bereits abonniert und gelesen wurden.
|
||||
@@ -1,14 +1,144 @@
|
||||
\chapter{Framework}
|
||||
\label{ch:framework}
|
||||
Um die Website-Erweiterung realisieren zu können, wird zunächst festgelegt welche Programmierschnittstellen verwendet werden. Im Web-Backend fällt die Wahl auf die objektorientierte Sprache Python, das ausschlie"slich Serverseitig anwendbar ist. Der Programmaufbau Pythons macht den Code leicht lesbar und der einfache Syntax ermöglicht einen strukturierte Implementierung der Website([Ndu17]). Ein entscheidende Vorteil hierbei ist das dazugehörige Web-Framework Django, auf das im folgenden Kapitel genauer eingegangen wird.
|
||||
Um die Website-Erweiterung realisieren zu können, wird zunächst festgelegt welche Programmierschnittstellen verwendet werden. Im Web-Backend fällt die Wahl auf die objektorientierte Sprache Python, die ausschlie"slich Serverseitig anwendbar ist. Der Programmaufbau Pythons macht den Code leicht lesbar und der einfache Syntax ermöglicht einen strukturierte Implementierung der Website([Ndu17]). Die vielen abstrakten Datentypen, wie dynamische Arrays und Wörterbücher, sind gro"sflächig einsetzbar.
|
||||
Ein entscheidender Vorteil hierbei ist das dazugehörige Framework Django, auf das im folgenden Kapitel genauer eingegangen wird.
|
||||
|
||||
|
||||
\section{Django}
|
||||
Django ist eine Erweiterung, die auf einer Model-View-Presenter (MVP) Architektur basiert. Ähnlich wie der Model-View-Controller sind die Interaktionen zwischen Model und View die Auswahl und Ausführung von Befehlen und das Auslösen von Ereignissen. Da die View aber hier bereits den Gro"steil des Controllers übernimmt, ist der MVP eine Überarbeitung. Der Teil, der Elemente des Modells auswählt, Operationen durchführt und alle Ereignisse kapselt, ergibt die Presenter-Klasse([She09]).
|
||||
auf die Daten vom Model zurück und das Model teilt der View mit, wenn sich Daten ändern. Da nun aber nahezu alle Aufgaben des Controllers von der View übernommen werden,
|
||||
Django ist ein Web-Framework, das auf einer Model-View-Presenter (MVP) Architektur basiert. Ähnlich wie der Model-View-Controller sind die Interaktionen zwischen Model und View die Auswahl und Ausführung von Befehlen und das Auslösen von Ereignissen (vgl. Abbildung 2.1). Da die View aber hier bereits den Gro"steil des Controllers übernimmt, ist der MVP eine Überarbeitung. Der Teil, der Elemente des Modells auswählt, Operationen durchführt und alle Ereignisse kapselt, ergibt die Presenter-Klasse([She09]). Durch die direkte Bindung von Daten und View, geregelt durch den Presenter, wird die Codemenge der Applikation stark reduziert.
|
||||
|
||||
\begin{figure}[!h]
|
||||
\centering
|
||||
\includegraphics[width=0.5\textwidth]{figures/MVP}
|
||||
\caption{Vereinfachter MVP}
|
||||
\hfill
|
||||
\end{figure}
|
||||
|
||||
Der Prozess vom Anfragen der URL über den Server, bis hin zur fertig gerenderten Website kann wie folgt vereinfacht darstellen. Der User gibt eine URL im Browser ein und sendet sie an den Web-Server.
|
||||
|
||||
Das Interface WSGI am Web-Server verbindet diesen mit dem Web-Framework, indem es den Request zum passenden Objekt weiterleitet. Hier wird der Applikation eine Callback-Funktion zur Verfügung gestellt [Kin17]. Au"serdem werden folgende Schritte durchgeführt:
|
||||
\begin{itemize}
|
||||
\item Die Middleware-Klassen aus der settings.py werden geladen
|
||||
\item Die Methoden der Listen Request, View, Response und Excpetion werden geladen
|
||||
\item Die angeforderte URL wird aufgelöst
|
||||
\end{itemize}
|
||||
|
||||
Der WSGI-Handler fungiert also als Pförtner und Manager zwischen dem Web-Server und dem Django-Projekt.
|
||||
Um die URL, wie weiter oben erwähnt, aufzulösen, benötigt WSGI einen urlresolver. Durch die explizite Zuweisung der vorhandenen Seiten, kann dieser über die regulären Ausdrücke der url.py-Datei iterieren. Gibt es eine Übereinstimmung, wird die damit verknüpfte Funktion in der View (view.py) aufgerufen. Hier ist die gesamte Logik der Website lokalisiert. Wie bereits erwähnt, ist es möglich unter Anderem auf die Datenbank der Applikation zuzugreifen und Eingaben des Users über eine Form zu verarbeiten. Nachdem werden die Informationen der View an das Template weitergereicht. Es handelt sich dabei um eine einfache HTML-Seite in der der strukturelle Aufbau im Frontend festgelegt wird. Die Informationen der View können hier zwischen doppelt-geschweiften Klammern eingebunden und, wenn nötig, mit einfachen Python-Befehlen angepasst werden. Nun kann das Template, die vom WSGI-Framework zur Verfügung gestellte Callback-Funktion befüllen und einen Response an den Web-Server schicken. Die fertige Seite ist beim Klienten im Browserfenster zum rendern bereit (vgl. Abbildung 2.2.).
|
||||
|
||||
\begin{figure}[!h]
|
||||
\centering
|
||||
\includegraphics[width=0.5\textwidth]{figures/request-response-cycle}
|
||||
\caption{Request-Response-Kreislauf des Django Frameworks}
|
||||
\hfill
|
||||
\end{figure}
|
||||
|
||||
\subsection {Besonderheiten}
|
||||
Das Django-Framework bringt einige Besonderheiten mit sich, die beim implementiern des Prototypen von Bedeutung sind. Diese werden im Folgenden beschrieben.
|
||||
|
||||
Die Administratoroberfläche ist eines der hilfreichsten Werkzeugen des gesamten Frameworks. Es stellt die Metadaten der Modelle aus dem Code visuell dar. Verifizierte Benutzer können die Daten nicht nur schnell erfassen, sondern diese auch editieren und verwalten. Das Recht, das Admin-Backend uneingeschränkt zu benutzen, ist dem sogenannten superuser vorenthalten. Dieser kann beim erstmaligen zuweisen nur über die Kommandozeile eingerichtet werden. Ist bereits ein superuser vorhanden, kann dieser im Admin-Backend weiteren Benutzern den gleichen Handlungsfreiraum einräumen. Zudem gibt es noch weitere Stufen der Zugangsberechtigungen, Staff- und Active-Status, die für eine breitere Gruppe von Benutzern geeignet ist.
|
||||
Um die gestaffelten Zugangsberechtigungen auch auf der Website umsetzen zu können, stellt Django verschiedene Decorator zur Verfügung. Soll eine bestimmte Seite nur von eingeloggten Benutzern besucht werden dürfen, so importiert man die Decorator des, von Django zur Verfügung gestellten, Authentifizierungssystems mit
|
||||
\\
|
||||
\noindent\hspace*{10mm}%
|
||||
from django.contrib.auth.decorators import login\_required
|
||||
\\
|
||||
Direkt über den Beginn der Funktion in view.py, oder auch single-view-function, wird zudem folgende Zeile ergänzt:
|
||||
\\
|
||||
\noindent\hspace*{10mm}%
|
||||
\makeatletter @login\_required
|
||||
\\
|
||||
Natürlich lassen sich die Decoratoren auch für andere Zwecke vor Funktionen platzieren. Begrenzte Zugänge zu den Views können durch die Art der Anfrage realisiert werden. Der Benutzer muss also zum Beispiel durch GET auf eine Seite zugreifen wollen um Einsicht zu erhalten.
|
||||
|
||||
Benutzerdefinierte Decorator sind im Django-Framework möglich, darauf wird hier aber nicht weiter eingegangen.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\section{Erweiterungen}
|
||||
|
||||
Die Programmiersprache Python bringt viele hilfreiche Erweiterungen mit sich. Die im folgenden aufgeführten sind hauptsächlich für die Paketverwaltung der Applikation zuständig.
|
||||
|
||||
Wird ein neues Projekt gestartet, ist es üblich, verschiedensten Programme und Module dafür zu verwenden. Die Versionen dieser spielen hierbei eine entscheidende Rolle, um Konflikte zu vermeiden [Fou18]. Um diesem Problem vorzubeugen, wird eine virtuelle Umgebung implementiert. Diese besitzt einen eigenen Projektpfad, beinhaltet alle nötigen Pakete und Bibliotheken, und lässt sich nach dem Einrichten im Terminal benutzten. Die folgende Abbildung (2.3) zeigt das Erstellen eines neunen Ordners, das Erstellen der virtuellen Umgebung und den Aktivierungsbefehl. Ist der Name des Environment in Klammern am Anfang der Zeile, bedeutet das, diese ist jetzt aktiv.
|
||||
|
||||
\begin{figure}[!h]
|
||||
\centering
|
||||
\includegraphics[width=0.7\textwidth]{figures/virt-env-terminal}
|
||||
\caption{Erstellen der virtuelle Umgebung im Terminal}
|
||||
\hfill
|
||||
\end{figure}
|
||||
|
||||
Die Umgebung ist jetzt bereit befüllt zu werden. Um die Pakete und Module kollisionsfrei zu installieren ist es empfehlenswert einen Package-Manager zu verwenden. Mit pip können diese installiert, geupdated und gelöscht werden. Au"serdem kann der Manager Abhängigkeiten, wenn nötig, überschreiben und optimieren. Falls ein, sich von der neuesten Version unterscheidendes, Programm installiert werden soll, so ist dies ebenso möglich.
|
||||
|
||||
Eine weitere hilfreiche Erweiterung ist pylint. Das Tool sucht nicht nur nach Fehlern im Code, sondern versucht diesen sauber und einheitlich zu gestalten. Hierbei wird auf den Code-Standard PEP-8 geprüft [Dix18]. Die folgende Liste zeigt eine Kurzfassung der wichtigsten Regeln:
|
||||
|
||||
\begin{itemize}
|
||||
\item Einrückung, meist 4 Leerzeichen
|
||||
\item Maximale Zeichenanzahl pro Zeile
|
||||
\item Zwei Leerzeile zwischen Klassen und Funktionen
|
||||
\item Eine Leerzeile zwischen Methoden innerhalb einer Klasse
|
||||
\item Leerzeichen in Ausdrücke und Anweisungen vermeiden
|
||||
\item Die Reihenfolge der Importe: Standartbibliotheken, Drittanbieterbibliotheken, Lokale Anwendungen
|
||||
\item Konventionen der Namensgebung von Funktionen, Modulen usw.
|
||||
\end{itemize}
|
||||
Natürlich sind dies Vorgaben, die eingehalten werden können, aber nicht notwendig sind um den Code fertig kompilieren und ausgeben zu lassen.
|
||||
|
||||
Das ldap, Lightweight Directory Access Protocol, muss als Erweiterung in die hier bearbeitende Bachelor-Arbeit eingebunden werden. Dies ist ein Internetprotokoll, welches die Kommunikation mit dem Hochschulinternen Active Directory verwaltet. Es wird eingesetzt um Benutzer so schnell und effizient wie möglich durch eine bereits existierende Datenbank abzufragen und zu authentifizieren. Der Aufbau ist mit einem Baum zu vergleichen (vgl. Abbildung 2.4.). Die Wurzel besteht aus sehr allgemeinen Informationen, umso näher man den Blättern kommt, umso spezifischer werden diese. Ein Objekt in der Struktur wird durch einen einmaligen Namen identifiziert, der aus den gesamten hinterlegten Informationen besteht. Der Name für den in der Abbildung 2.4 dargestellten Baum wäre \glqq cn=John Doe, ou=People, dc=sun.com\grqq.
|
||||
|
||||
\begin{figure}[!h]
|
||||
\centering
|
||||
\includegraphics[width=0.5\textwidth]{figures/ldap-tree}
|
||||
\caption{Beispiel eines LDAP-Trees}
|
||||
\hfill
|
||||
\end{figure}
|
||||
|
||||
\section{Erweiterung}
|
||||
\subsection {Taggable-Manager}
|
||||
Django-taggit ist eine Erweiterung von Alex Gaynor, einem Entwickler aus Washingtion DC. Das Add-on ermöglicht das Verwenden von Tags die automatisch mit einem eindeutigen Slug versehen werden. Der darin enthaltene Taggable Manager verwendet Django's Contenttype Framework, welches per Default verwendet wird, um die Modelle der Applikation zu verfolgen und diese durch generische Beziehungen zu verknüpfen. Die Felder app\_label und model machen die Modelle eindeutig zuweisbar. Instanzen des Contenttypes präsentieren und speichern die Informationen und Erstellen automatisch neue Instanzen, wenn Modelle hinzugefügt werden. Zudem stehen Methoden zur Verfügung, die das Abrufen und Arbeiten mit Instanzen der einzelnen Modelle erleichtern.
|
||||
|
||||
Der Taggable-Manager ist jedoch nicht an das Contenttype-Framework gebunden ([Her16]). Durch die Verwendung eines echten Fremdschlüssels, kann zum Beispiel die Performance und Referenzgarantie verwirklicht werden. Dazu ist lediglich die Erstellung einer eigenen lookup-Tabelle notwendig, die die Entitäten zweier Tabellen direkt verlinkt, anstatt diese generische zu verbinden. Weiterführend können Modelle in einem benutzerdefinierten Modell vereint werden, sodass er Zugriff auf diese einheitlich geschieht. Außerdem ist es möglich Primary-Keys zu verwenden, die nicht aus ganzen Zahlen bestehen, sondern aus Buchstaben und Wörtern.
|
||||
|
||||
Um django-taggit zu installieren wird der folgende Befehl in die Kommandozeile eingefügt([Gay10]):
|
||||
\\
|
||||
\noindent\hspace*{10mm}%
|
||||
\$ pip install django-taggit
|
||||
\\
|
||||
Im model.py wird das Feld tag neu erstellt und als Taggable Manager definiert.
|
||||
Au"serdem muss taggit in der settings.py unter INSTALLED\_APPS ergänzt werden. Um dem Programm zu sagen, dass nun eine neue Liste der Datenbank hinzugefügt werden muss, werden folgende Befehle in die Kommandozeile eingefügt:
|
||||
\\
|
||||
\noindent\hspace*{10mm}%
|
||||
\$ python3 manage.py makemigrations \\
|
||||
\noindent\hspace*{10mm}%
|
||||
\$ python3 manage.py migrate
|
||||
\\
|
||||
Im Admin-Backend kann nun geprüft werden, ob das neue Feld in die Datenbank integriert wurde. Neue Tags können in das Textfeld eingetragen werden. Der Parser verarbeitet jedes Wort, dass durch ein Komma oder ein Leerzeichen getrennt ist als ein Tag. Soll dieses jedoch aus mehreren Wörtern bestehen so müssen diese mit Anführungszeichen umfasst werden. Standardmäßig unterscheidet der Taggable Manager zwischen Groß- und Kleinschreibung, Tags sind also case sensitive. Ändern kann man das, indem der Boolean TAGGIT\_CASE\_INSENSITIVE in der settings.py auf True gestellt wird.
|
||||
|
||||
|
||||
|
||||
|
||||
\section{Bootstrap}
|
||||
Eine umfangreiche Website einheitlich zu gestalten ist oft sehr komplex und zeitaufwendig. Die Entwickler von Twitter haben deshalb, zunächst Firmenintern, an einem neuen Verwaltungswerkzeug gearbeitet, das mehrere Bibliotheken zusammenführen sollte. Sie merkten, das die neue Bibliothek, die daraus entstand, nicht nur auf Ihre eigene Website anwendbar, sondern so flexible ist, dass jede Art von Website davon profitieren könnte. 2011 entschieden Sie sich Bootstrap für die Öffentlichkeit frei zugänglich zu machen. Die Open-Source-Bibliothek, die auf GitHub abrufbar ist, wird seitdem von vielen interessierten Programmierern weiterentwickelt und ist somit stark gewachsen. Version 2.0 verfügt au"serdem über die Fähigkeit Websites responsive auf verschiedenste mobile Endgeräte anzupassen.
|
||||
|
||||
Das Bootstrap-Paket beinhaltet vorgefertigte Cascading Stylesheets, kurz CSS, die Farben, Schriftarten und viele weitere Stildefinitionen. Zudem befinden sich auch Erweiterungen des JavaScript-Frameworks jQuery in der Bibliothek, die weiterführende Funktionen beinhalten wie zum Beispiel Filter oder Dropdown-Menüs. Das Paket kann einfach eingebunden werden im head-tag einer HTML-Datei (vgl. Abbildung 2.3). Das bedeutet, dass Medie-Queries oder ähnliche Methoden nicht mehr nötig sind, nicht nur um eine Website mobilfähig zu machen, sondern auch kompatibel für die verschiedensten Browser.
|
||||
|
||||
\begin{figure}[!h]
|
||||
\centering
|
||||
\includegraphics[width=1\textwidth]{figures/bootstrap-head-tag}
|
||||
\caption{Einbindung von Bootstrap in einer HTML-Datei}
|
||||
\hfill
|
||||
\end{figure}
|
||||
|
||||
Durch das Einbinden von Bootstrap in einer HTML-Datei werden einige Styles bereits automatisch auf die darin vorkommenden Tags, wie Links und Überschriften, angewandt. Dies ist jedoch nur ein sehr kleiner Teil den die Bibliothek zur Verfügung stellt. Möchte man Bootstrap umfangreich nutzen so lassen sich die Stildefinitionen mit Klassen oder ID's in diverse HTML-Tags eintragen (vlg. Abbildung 2.4.).
|
||||
|
||||
\begin{figure}[!h]
|
||||
\centering
|
||||
\includegraphics[width=1\textwidth]{figures/bootstrap-class-example}
|
||||
\caption{Bootstrap-Klassen in HTML-Tag}
|
||||
\hfill
|
||||
\end{figure}
|
||||
|
||||
Möchte man bestimmte gestalterische Eigenschaften von Bootstrap überschreiben muss eine eigens verfasste CSS-Datei nach der Verlinkung von Bootstrap in die Website eingebunden werden. Der Parser liest die Datei von oben nach unten, Links nach Rechts. Liest dieser also zu erst die Bootstrap Bibliothek und speichert diese, so überschreiben die Styles die danach kommen, die bereits gelesenen Eingaben. Die Styles, die inline auf ein Tag angewendet werden sind somit die bestimmenden Eigenschaften. Natürlich sollten Stildefinitionen niemals inline eingepflegt werden, da dies zu einem sehr unübersichtlichen und wartungsintensiven Code führen.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,25 @@
|
||||
\chapter{Prototyp}
|
||||
\label{ch:prototyp}
|
||||
Um zu beweisen, wie eine Spcial Media Plattform die Mail-Flut der Efi-Fakultät reduzieren kann, wird ein Prototyp implementiert.
|
||||
|
||||
\section{Organisation}
|
||||
Grundlegender Aufbau der Website, Verwaltung der Daten evlt auf nochmal Taggable-Manager (ManyToMany) ...
|
||||
|
||||
\subsection{Verwaltung im Administrator-Backend}
|
||||
Näher auf CustomUserModel eingehen, Diagramm erstellen und einbinden
|
||||
|
||||
\subsection{Berechtigung der User}
|
||||
Welche Berechtigungen gibt es im Prototyp, welche werden vom Active Directory übernommen?
|
||||
|
||||
|
||||
\section{Funktion}
|
||||
Nötige Funktionen
|
||||
|
||||
\subsection{Abonnieren}
|
||||
Tags als eingeloggter User abonnieren und verwalten Front-end und Admin-Backend?
|
||||
|
||||
\subsection{Filtern}
|
||||
\subsection{Benachrichtigung}
|
||||
Tag-map? Filtern nach abonnierten Posts, alle Posts und Posts mit bestimmten Tags
|
||||
|
||||
\subsection{Benachrichtigung}
|
||||
Mail-Benachrichtigung wöchentlich
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 534 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
@@ -1,19 +1,55 @@
|
||||
@article{Verdam,
|
||||
@article{Leipner,
|
||||
author = "Ingo Leipner",
|
||||
title = "Stress für Beschäftigte: Wie kann man die E-Mail-Flut bekämpfen",
|
||||
year = "2013",
|
||||
note = "http://www.mz-web.de/wirtschaft/e-mail-flut-mails-bearbeiten-kommunikation-stress-zeit-sparen" }
|
||||
note = "http://www.mz-web.de/wirtschaft/e-mail-flut-mails-bearbeiten-kommunikation-stress-zeit-sparen"
|
||||
}
|
||||
|
||||
@article{Ndukwe,
|
||||
@article{Ndukwe,
|
||||
author = "Nnenna Ndukwe",
|
||||
title = "Python is the back-end programming language of the future and here’s why",
|
||||
year = "2017",
|
||||
note = "https://medium.com/@nnennahacks/https-medium-com-nnennandukwe-python-is-the-back-end-programming-language-of-the-future-heres-why" }
|
||||
note = "https://medium.com/@nnennahacks/https-medium-com-nnennandukwe-python-is-the-back-end-programming-language-of-the-future-heres-why"
|
||||
}
|
||||
|
||||
@article{Shelest,
|
||||
@article{Shelest,
|
||||
author = "Alexy Shelest",
|
||||
title = "Model View Controller, Model View Presenter, and Model View ViewModel Design Patterns",
|
||||
year = "2009",
|
||||
note = "https://www.codeproject.com/Articles/42830/Model-View-Controller-Model-View-Presenter-and-Mod" }
|
||||
note = "https://www.codeproject.com/Articles/42830/Model-View-Controller-Model-View-Presenter-and-Mod"
|
||||
}
|
||||
|
||||
@article{Gaynor,
|
||||
author = "Alex Gaynor",
|
||||
title = "Exploring Django-Taggit’s Data Model",
|
||||
year = "2010",
|
||||
note = "https://django-taggit.readthedocs.io/en/latest/getting\_started"
|
||||
}
|
||||
|
||||
|
||||
@article{Herzog,
|
||||
author = "Stephan Herzog",
|
||||
title = "Model View Controller, Model View Presenter, and Model View ViewModel Design Patterns",
|
||||
year = "2016",
|
||||
note = "https://medium.com/sthzg/a-short-exploration-of-django-taggit-bb869ea5051f"
|
||||
}
|
||||
|
||||
@article{King,
|
||||
author = "Adam King",
|
||||
title = "Django Middlewares and the Request/Response Cycle",
|
||||
year = "2017",
|
||||
note = "https://medium.com/zeitcode/django-middlewares-and-the-request-response-cycle-fcbf8efb903f"
|
||||
}
|
||||
|
||||
@article{Python,
|
||||
author = "Python Software Foundation",
|
||||
title = "Virtual Environments and Packages",
|
||||
year = "2018",
|
||||
note = "https://docs.python.org/3/tutorial/venv.html"
|
||||
}
|
||||
|
||||
@article{Dixit,
|
||||
author = "Chitrank Dixit",
|
||||
title = "PEP-8 Tutorial: Code Standards in Python",
|
||||
year = "2018",
|
||||
note = "https://www.datacamp.com/community/tutorials/pep8-tutorial-python-code"
|
||||
}
|
||||
@@ -0,0 +1,405 @@
|
||||
[16/Oct/2018 19:58:49] INFO [mysite:150] test
|
||||
[16/Oct/2018 20:00:13] INFO [mysite:150] test
|
||||
[16/Oct/2018 20:00:44] INFO [mysite:150] test
|
||||
[18/Oct/2018 16:49:10] INFO [mysite:150] test
|
||||
[18/Oct/2018 16:50:20] INFO [mysite:149] test
|
||||
[18/Oct/2018 16:53:59] INFO [mysite:149] test
|
||||
[18/Oct/2018 17:02:15] INFO [mysite:149] Here ist the log
|
||||
[18/Oct/2018 17:03:03] INFO [mysite:149] Here ist the log
|
||||
[18/Oct/2018 17:04:21] INFO [mysite:150] Here ist the log
|
||||
[18/Oct/2018 17:08:44] INFO [mysite:150] Here ist the log
|
||||
[18/Oct/2018 17:22:00] INFO [mysite:150] Here ist the log
|
||||
[18/Oct/2018 17:29:57] INFO [mysite:150] Here ist the log
|
||||
[18/Oct/2018 17:33:51] INFO [mysite:150] Here ist the log
|
||||
[18/Oct/2018 17:37:15] INFO [mysite:147] hei
|
||||
[18/Oct/2018 17:38:10] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 17:40:53] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 17:41:34] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 17:41:45] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 17:42:04] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 17:47:59] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 17:49:27] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 17:49:43] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 17:50:18] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 18:04:38] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 18:07:12] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 18:08:17] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 18:09:29] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 18:10:27] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 18:10:59] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 18:13:11] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 18:14:22] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 18:14:45] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 18:17:07] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 18:23:37] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 18:42:53] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 18:43:28] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 18:46:58] INFO [mysite:147] CustomUser object (25)
|
||||
[18/Oct/2018 19:12:55] INFO [mysite:147] CustomUser object (25)
|
||||
[19/Oct/2018 09:18:42] INFO [mysite:147] CustomUser object (25)
|
||||
[19/Oct/2018 09:19:10] INFO [mysite:148] <QuerySet []>
|
||||
[19/Oct/2018 10:24:35] INFO [mysite:148] <QuerySet []>
|
||||
[19/Oct/2018 16:52:08] INFO [mysite:148] <QuerySet []>
|
||||
[19/Oct/2018 17:33:50] INFO [mysite:149] CustomUser object (25)
|
||||
[19/Oct/2018 17:38:33] INFO [mysite:149] CustomUser object (25)
|
||||
[19/Oct/2018 17:39:08] INFO [mysite:149] CustomUser object (25)
|
||||
[19/Oct/2018 17:41:43] INFO [mysite:149] CustomUser object (25)
|
||||
[19/Oct/2018 17:42:00] INFO [mysite:149] CustomUser object (25)
|
||||
[19/Oct/2018 17:44:10] INFO [mysite:149] CustomUser object (25)
|
||||
[19/Oct/2018 17:47:28] INFO [mysite:149] CustomUser object (25)
|
||||
[19/Oct/2018 17:48:28] INFO [mysite:149] CustomUser object (25)
|
||||
[19/Oct/2018 17:56:41] INFO [mysite:149] CustomUser object (25)
|
||||
[19/Oct/2018 18:06:57] INFO [mysite:149] CustomUser object (25)
|
||||
[19/Oct/2018 18:07:17] INFO [mysite:149] CustomUser object (25)
|
||||
[19/Oct/2018 18:07:31] INFO [mysite:149] CustomUser object (25)
|
||||
[19/Oct/2018 18:12:56] INFO [mysite:149] CustomUser object (25)
|
||||
[19/Oct/2018 18:15:29] INFO [mysite:149] CustomUser object (25)
|
||||
[20/Oct/2018 17:20:58] INFO [mysite:149] CustomUser object (25)
|
||||
[20/Oct/2018 17:54:57] INFO [mysite:149] CustomUser object (25)
|
||||
[20/Oct/2018 18:03:09] INFO [mysite:149] CustomUser object (25)
|
||||
[20/Oct/2018 18:18:52] INFO [mysite:149] CustomUser object (25)
|
||||
[20/Oct/2018 19:14:57] INFO [mysite:183] None
|
||||
[20/Oct/2018 19:15:00] INFO [mysite:183] test
|
||||
[20/Oct/2018 19:15:45] INFO [mysite:183] test
|
||||
[20/Oct/2018 19:17:52] INFO [mysite:183] test
|
||||
[20/Oct/2018 19:18:31] INFO [mysite:183] test
|
||||
[20/Oct/2018 19:19:01] INFO [mysite:183] test
|
||||
[20/Oct/2018 19:20:08] INFO [mysite:184] test
|
||||
[20/Oct/2018 19:24:45] INFO [mysite:184] None
|
||||
[20/Oct/2018 19:26:30] INFO [mysite:184] None
|
||||
[20/Oct/2018 19:29:44] INFO [mysite:184] test
|
||||
[20/Oct/2018 19:32:09] INFO [mysite:184] test
|
||||
[20/Oct/2018 19:33:14] INFO [mysite:184] 5
|
||||
[20/Oct/2018 22:26:02] INFO [mysite:184] hi
|
||||
[20/Oct/2018 22:26:09] INFO [mysite:184] 2
|
||||
[20/Oct/2018 22:26:39] INFO [mysite:184] 2
|
||||
[20/Oct/2018 22:35:49] INFO [mysite:183] 2
|
||||
[20/Oct/2018 22:35:55] INFO [mysite:183] 3
|
||||
[20/Oct/2018 22:51:06] INFO [mysite:183] hi
|
||||
[20/Oct/2018 22:53:24] INFO [mysite:183] hi
|
||||
[20/Oct/2018 22:54:12] INFO [mysite:183] hi
|
||||
[20/Oct/2018 22:57:38] INFO [mysite:181] <QuerySet [<Post: first post>, <Post: second bla>, <Post: Third one>]>
|
||||
[20/Oct/2018 22:57:39] INFO [mysite:184] hi
|
||||
[20/Oct/2018 22:59:11] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 22:59:11] INFO [mysite:184] hi
|
||||
[20/Oct/2018 23:01:53] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:01:53] INFO [mysite:184] hi
|
||||
[20/Oct/2018 23:02:06] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:02:06] INFO [mysite:184] 5
|
||||
[20/Oct/2018 23:02:22] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:02:22] INFO [mysite:184] 5
|
||||
[20/Oct/2018 23:02:45] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:02:45] INFO [mysite:184] 5
|
||||
[20/Oct/2018 23:03:07] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:03:07] INFO [mysite:184] 5
|
||||
[20/Oct/2018 23:03:46] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:03:46] INFO [mysite:184] 5
|
||||
[20/Oct/2018 23:04:35] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:04:35] INFO [mysite:184] 5
|
||||
[20/Oct/2018 23:06:49] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:06:49] INFO [mysite:184] hi
|
||||
[20/Oct/2018 23:15:41] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:15:41] INFO [mysite:184] hi
|
||||
[20/Oct/2018 23:17:19] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:17:19] INFO [mysite:184] hi
|
||||
[20/Oct/2018 23:17:38] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:17:38] INFO [mysite:184] hi
|
||||
[20/Oct/2018 23:19:11] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:19:11] INFO [mysite:184] hi
|
||||
[20/Oct/2018 23:24:22] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:24:23] INFO [mysite:184] hi
|
||||
[20/Oct/2018 23:24:42] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:24:42] INFO [mysite:184] hi
|
||||
[20/Oct/2018 23:24:49] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:24:49] INFO [mysite:184] hi
|
||||
[20/Oct/2018 23:24:54] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:24:54] INFO [mysite:184] test
|
||||
[20/Oct/2018 23:25:01] INFO [mysite:181] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[20/Oct/2018 23:25:01] INFO [mysite:184] third
|
||||
[20/Oct/2018 23:28:54] INFO [mysite:182] None
|
||||
[20/Oct/2018 23:29:00] INFO [mysite:182] hi
|
||||
[20/Oct/2018 23:29:42] INFO [mysite:182] hi
|
||||
[20/Oct/2018 23:30:53] INFO [mysite:182] hi
|
||||
[20/Oct/2018 23:34:29] INFO [mysite:184] hi
|
||||
[20/Oct/2018 23:34:34] INFO [mysite:54] <QuerySet [<Post: second bla>]>
|
||||
[20/Oct/2018 23:38:12] INFO [mysite:54] <QuerySet [<Post: second bla>]>
|
||||
[20/Oct/2018 23:38:18] INFO [mysite:184] None
|
||||
[20/Oct/2018 23:38:25] INFO [mysite:184] hi
|
||||
[20/Oct/2018 23:40:03] INFO [mysite:184] hi
|
||||
[20/Oct/2018 23:40:10] INFO [mysite:184] first
|
||||
[20/Oct/2018 23:41:01] INFO [mysite:184] first
|
||||
[20/Oct/2018 23:41:12] INFO [mysite:184] h
|
||||
[20/Oct/2018 23:41:28] INFO [mysite:184] h
|
||||
[20/Oct/2018 23:41:32] INFO [mysite:184] h
|
||||
[20/Oct/2018 23:41:38] INFO [mysite:184] h
|
||||
[20/Oct/2018 23:41:40] INFO [mysite:184] hi
|
||||
[20/Oct/2018 23:41:50] INFO [mysite:184] hi
|
||||
[20/Oct/2018 23:41:56] INFO [mysite:184] taggit
|
||||
[21/Oct/2018 10:35:50] INFO [mysite:184] taggit
|
||||
[21/Oct/2018 10:35:55] INFO [mysite:184]
|
||||
[21/Oct/2018 10:38:17] INFO [mysite:184] None
|
||||
[21/Oct/2018 12:59:59] INFO [mysite:184] None
|
||||
[22/Oct/2018 14:31:54] INFO [mysite:184] None
|
||||
[22/Oct/2018 14:32:03] INFO [mysite:150] CustomUser object (25)
|
||||
[22/Oct/2018 14:40:08] INFO [mysite:150] CustomUser object (25)
|
||||
[22/Oct/2018 14:43:18] INFO [mysite:150] CustomUser object (25)
|
||||
[22/Oct/2018 14:43:31] INFO [mysite:150] CustomUser object (25)
|
||||
[22/Oct/2018 14:50:32] INFO [mysite:150] esthi
|
||||
[22/Oct/2018 14:50:32] INFO [mysite:152] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 14:51:10] INFO [mysite:150] stefan
|
||||
[22/Oct/2018 14:51:10] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 14:56:36] INFO [mysite:150] stefan
|
||||
[22/Oct/2018 14:56:36] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 14:56:56] INFO [mysite:150] stefan
|
||||
[22/Oct/2018 14:56:56] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 14:57:15] INFO [mysite:150] stefan
|
||||
[22/Oct/2018 14:57:15] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 14:57:39] INFO [mysite:150] stefan
|
||||
[22/Oct/2018 14:57:39] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 14:58:53] INFO [mysite:150] stefan
|
||||
[22/Oct/2018 14:58:53] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 14:59:01] INFO [mysite:150] stefan
|
||||
[22/Oct/2018 14:59:01] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 14:59:55] INFO [mysite:150] stefan
|
||||
[22/Oct/2018 14:59:55] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 15:02:16] INFO [mysite:150] stefan
|
||||
[22/Oct/2018 15:02:16] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 15:03:09] INFO [mysite:150] stefan
|
||||
[22/Oct/2018 15:03:09] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 15:03:41] INFO [mysite:150] stefan
|
||||
[22/Oct/2018 15:03:41] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 15:05:17] INFO [mysite:184] None
|
||||
[22/Oct/2018 15:05:21] INFO [mysite:184] hi
|
||||
[22/Oct/2018 15:07:51] INFO [mysite:185] None
|
||||
[22/Oct/2018 15:07:53] INFO [mysite:150] stefan
|
||||
[22/Oct/2018 15:07:53] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 15:08:37] INFO [mysite:150] stefan
|
||||
[22/Oct/2018 15:08:37] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 15:09:08] INFO [mysite:151] stefan
|
||||
[22/Oct/2018 15:09:08] INFO [mysite:153] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 15:09:58] INFO [mysite:151] stefan
|
||||
[22/Oct/2018 15:09:58] INFO [mysite:153] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 15:11:00] INFO [mysite:151] stefan
|
||||
[22/Oct/2018 15:11:00] INFO [mysite:153] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 15:11:41] INFO [mysite:151] stefan
|
||||
[22/Oct/2018 15:11:41] INFO [mysite:153] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 15:12:14] INFO [mysite:151] stefan
|
||||
[22/Oct/2018 15:12:14] INFO [mysite:153] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 15:14:15] INFO [mysite:151] stefan
|
||||
[22/Oct/2018 15:14:15] INFO [mysite:153] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 17:37:38] INFO [mysite:154] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 17:38:19] INFO [mysite:154] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:39:44] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:39:44] INFO [mysite:155] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:41:03] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:41:19] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:41:20] INFO [mysite:155] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:45:07] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:45:07] INFO [mysite:155] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:45:32] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:45:32] INFO [mysite:155] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:45:47] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:45:47] INFO [mysite:155] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:45:47] INFO [mysite:160] ['bamberg']
|
||||
[22/Oct/2018 17:45:47] INFO [mysite:160] ['bamberg', 'test']
|
||||
[22/Oct/2018 17:49:21] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:49:21] INFO [mysite:155] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:49:21] INFO [mysite:159] ['bamberg']
|
||||
[22/Oct/2018 17:49:21] INFO [mysite:159] ['bamberg', 'test']
|
||||
[22/Oct/2018 17:51:20] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:51:20] INFO [mysite:155] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:51:20] INFO [mysite:159] ['bamberg']
|
||||
[22/Oct/2018 17:51:20] INFO [mysite:159] ['bamberg', 'test']
|
||||
[22/Oct/2018 17:51:27] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:51:27] INFO [mysite:155] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:51:28] INFO [mysite:159] ['bamberg']
|
||||
[22/Oct/2018 17:51:28] INFO [mysite:159] ['bamberg', 'test']
|
||||
[22/Oct/2018 17:53:13] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:53:55] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:53:55] INFO [mysite:154] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:53:55] INFO [mysite:158] ['bamberg']
|
||||
[22/Oct/2018 17:53:55] INFO [mysite:158] ['bamberg', 'test']
|
||||
[22/Oct/2018 17:54:44] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:54:44] INFO [mysite:154] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:55:02] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:55:02] INFO [mysite:154] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:55:02] INFO [mysite:159] ['bamberg']
|
||||
[22/Oct/2018 17:55:02] INFO [mysite:159] ['bamberg', 'test']
|
||||
[22/Oct/2018 17:55:14] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:55:14] INFO [mysite:154] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:55:14] INFO [mysite:159] <QuerySet []>
|
||||
[22/Oct/2018 17:55:14] INFO [mysite:159] <QuerySet []>
|
||||
[22/Oct/2018 17:56:12] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:56:12] INFO [mysite:154] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:56:12] INFO [mysite:159] bamberg
|
||||
[22/Oct/2018 17:56:12] INFO [mysite:159] test
|
||||
[22/Oct/2018 17:56:34] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:56:34] INFO [mysite:154] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:56:34] INFO [mysite:159] bamberg
|
||||
[22/Oct/2018 17:56:34] INFO [mysite:159] test
|
||||
[22/Oct/2018 17:57:48] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:57:48] INFO [mysite:154] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:57:49] INFO [mysite:159] <QuerySet []>
|
||||
[22/Oct/2018 17:57:49] INFO [mysite:159] <QuerySet []>
|
||||
[22/Oct/2018 17:59:46] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:59:46] INFO [mysite:154] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 17:59:46] INFO [mysite:159] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 17:59:46] INFO [mysite:159] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 18:00:06] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 18:00:06] INFO [mysite:154] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:00:06] INFO [mysite:159] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 18:00:06] INFO [mysite:159] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 18:00:15] INFO [mysite:151] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 18:00:15] INFO [mysite:154] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:00:15] INFO [mysite:159] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 18:00:15] INFO [mysite:159] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 18:01:25] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:01:25] INFO [mysite:158] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 18:01:25] INFO [mysite:158] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 18:01:45] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:02:47] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:03:12] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:03:12] INFO [mysite:158] <QuerySet []>
|
||||
[22/Oct/2018 18:03:12] INFO [mysite:158] <QuerySet []>
|
||||
[22/Oct/2018 18:04:45] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:05:24] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:05:24] INFO [mysite:157] bamberg
|
||||
[22/Oct/2018 18:05:24] INFO [mysite:159] <QuerySet []>
|
||||
[22/Oct/2018 18:05:24] INFO [mysite:157] test
|
||||
[22/Oct/2018 18:05:24] INFO [mysite:159] <QuerySet []>
|
||||
[22/Oct/2018 18:13:35] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:13:35] INFO [mysite:157] bamberg
|
||||
[22/Oct/2018 18:14:16] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:14:16] INFO [mysite:157] bamberg
|
||||
[22/Oct/2018 18:19:16] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:19:16] INFO [mysite:157] bamberg
|
||||
[22/Oct/2018 18:38:14] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:38:14] INFO [mysite:157] bamberg
|
||||
[22/Oct/2018 18:41:50] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:41:50] INFO [mysite:157] bamberg
|
||||
[22/Oct/2018 18:41:50] INFO [mysite:159] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 18:41:50] INFO [mysite:157] test
|
||||
[22/Oct/2018 18:41:50] INFO [mysite:159] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[22/Oct/2018 18:45:55] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:45:55] INFO [mysite:157] bamberg
|
||||
[22/Oct/2018 18:46:39] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:46:39] INFO [mysite:157] bamberg
|
||||
[22/Oct/2018 18:46:39] INFO [mysite:159] <QuerySet []>
|
||||
[22/Oct/2018 18:46:39] INFO [mysite:157] test
|
||||
[22/Oct/2018 18:46:39] INFO [mysite:159] <QuerySet [<Post: first post>, <Post: second bla>, <Post: Third one>]>
|
||||
[22/Oct/2018 18:47:12] INFO [mysite:153] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 18:47:12] INFO [mysite:157] stefan
|
||||
[22/Oct/2018 18:47:12] INFO [mysite:159] <QuerySet []>
|
||||
[22/Oct/2018 18:48:22] INFO [mysite:153] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 18:48:22] INFO [mysite:157] stefan
|
||||
[22/Oct/2018 18:48:22] INFO [mysite:159] <QuerySet [<Post: Crazy>]>
|
||||
[22/Oct/2018 18:50:37] INFO [mysite:153] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 18:50:38] INFO [mysite:157] stefan
|
||||
[22/Oct/2018 18:52:01] INFO [mysite:153] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 18:52:01] INFO [mysite:157] stefan
|
||||
[22/Oct/2018 18:52:36] INFO [mysite:153] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 18:52:36] INFO [mysite:157] stefan
|
||||
[22/Oct/2018 18:53:07] INFO [mysite:153] <QuerySet [<Tag: stefan>]>
|
||||
[22/Oct/2018 18:53:07] INFO [mysite:157] stefan
|
||||
[22/Oct/2018 18:53:20] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:53:20] INFO [mysite:157] bamberg
|
||||
[22/Oct/2018 18:53:20] INFO [mysite:157] test
|
||||
[22/Oct/2018 18:54:05] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:54:05] INFO [mysite:157] bamberg
|
||||
[22/Oct/2018 18:54:20] INFO [mysite:153] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:54:21] INFO [mysite:157] bamberg
|
||||
[22/Oct/2018 18:54:21] INFO [mysite:157] test
|
||||
[22/Oct/2018 18:54:46] INFO [mysite:152] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:54:46] INFO [mysite:156] bamberg
|
||||
[22/Oct/2018 18:54:46] INFO [mysite:156] test
|
||||
[22/Oct/2018 18:55:43] INFO [mysite:152] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[22/Oct/2018 18:55:43] INFO [mysite:156] bamberg
|
||||
[22/Oct/2018 18:55:43] INFO [mysite:156] test
|
||||
[24/Oct/2018 15:10:56] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[24/Oct/2018 15:10:56] INFO [mysite:156] stefan
|
||||
[24/Oct/2018 15:11:37] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[24/Oct/2018 15:11:37] INFO [mysite:156] stefan
|
||||
[24/Oct/2018 15:11:37] INFO [mysite:158] <QuerySet []>
|
||||
[24/Oct/2018 15:13:48] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[24/Oct/2018 15:13:48] INFO [mysite:156] stefan
|
||||
[24/Oct/2018 15:13:48] INFO [mysite:158] <QuerySet []>
|
||||
[24/Oct/2018 15:15:46] INFO [mysite:153] <QuerySet [<Tag: stefan>]>
|
||||
[24/Oct/2018 15:15:46] INFO [mysite:157] stefan
|
||||
[24/Oct/2018 15:15:55] INFO [mysite:153] <QuerySet [<Tag: stefan>]>
|
||||
[24/Oct/2018 15:15:55] INFO [mysite:157] stefan
|
||||
[24/Oct/2018 15:15:55] INFO [mysite:159] <QuerySet []>
|
||||
[24/Oct/2018 15:17:17] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[24/Oct/2018 15:17:17] INFO [mysite:156] stefan
|
||||
[24/Oct/2018 15:17:17] INFO [mysite:158] <QuerySet []>
|
||||
[24/Oct/2018 15:18:27] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[24/Oct/2018 15:18:27] INFO [mysite:156] stefan
|
||||
[24/Oct/2018 15:18:27] INFO [mysite:158] <QuerySet []>
|
||||
[24/Oct/2018 15:21:10] INFO [mysite:150] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[24/Oct/2018 15:21:10] INFO [mysite:154] <QuerySet [<Tag: stefan>]>
|
||||
[24/Oct/2018 15:21:10] INFO [mysite:158] stefan
|
||||
[24/Oct/2018 15:21:10] INFO [mysite:160] <QuerySet []>
|
||||
[24/Oct/2018 15:22:12] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[24/Oct/2018 15:22:12] INFO [mysite:156] ['stefan']
|
||||
[24/Oct/2018 15:22:12] INFO [mysite:158] <QuerySet []>
|
||||
[24/Oct/2018 15:22:29] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[24/Oct/2018 15:22:29] INFO [mysite:156] ['stefan']
|
||||
[24/Oct/2018 15:22:57] INFO [mysite:152] <QuerySet [<Tag: stefan>]>
|
||||
[24/Oct/2018 15:22:57] INFO [mysite:155] <QuerySet []>
|
||||
[24/Oct/2018 15:23:36] INFO [mysite:152] <QuerySet [<Tag: stefan>, <Tag: test>]>
|
||||
[24/Oct/2018 15:23:36] INFO [mysite:155] <QuerySet []>
|
||||
[24/Oct/2018 15:23:36] INFO [mysite:155] <QuerySet [<Post: Third one>, <Post: first post>, <Post: second bla>]>
|
||||
[24/Oct/2018 15:24:29] INFO [mysite:152] <QuerySet [<Tag: bamberg>, <Tag: test>, <Tag: wieder>]>
|
||||
[24/Oct/2018 15:24:29] INFO [mysite:155] <QuerySet []>
|
||||
[24/Oct/2018 15:24:29] INFO [mysite:155] <QuerySet [<Post: Third one>, <Post: first post>, <Post: second bla>]>
|
||||
[24/Oct/2018 15:24:29] INFO [mysite:155] <QuerySet []>
|
||||
[24/Oct/2018 15:26:03] INFO [mysite:152] <QuerySet [<Tag: lukas>, <Tag: hi>]>
|
||||
[24/Oct/2018 15:26:03] INFO [mysite:155] <QuerySet []>
|
||||
[24/Oct/2018 15:26:03] INFO [mysite:155] <QuerySet [<Post: Third one>, <Post: second bla>]>
|
||||
[24/Oct/2018 15:51:54] INFO [mysite:152] <QuerySet [<Tag: bamberg>, <Tag: test>, <Tag: wieder>]>
|
||||
[24/Oct/2018 15:51:55] INFO [mysite:155] <QuerySet []>
|
||||
[24/Oct/2018 15:51:55] INFO [mysite:155] <QuerySet [<Post: Third one>, <Post: first post>, <Post: second bla>]>
|
||||
[24/Oct/2018 15:51:55] INFO [mysite:155] <QuerySet []>
|
||||
[24/Oct/2018 15:53:01] INFO [mysite:152] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[24/Oct/2018 15:53:01] INFO [mysite:155] <QuerySet []>
|
||||
[24/Oct/2018 15:53:01] INFO [mysite:155] <QuerySet [<Post: Third one>, <Post: first post>, <Post: second bla>]>
|
||||
[24/Oct/2018 15:53:28] INFO [mysite:152] <QuerySet [<Tag: bamberg>, <Tag: test>, <Tag: this is a new one>]>
|
||||
[24/Oct/2018 15:53:28] INFO [mysite:155] <QuerySet []>
|
||||
[24/Oct/2018 15:53:28] INFO [mysite:155] <QuerySet [<Post: Third one>, <Post: first post>, <Post: second bla>]>
|
||||
[24/Oct/2018 15:53:28] INFO [mysite:155] <QuerySet []>
|
||||
[24/Oct/2018 18:41:24] INFO [mysite:186] None
|
||||
[24/Oct/2018 18:41:31] INFO [mysite:186] bla
|
||||
[24/Oct/2018 18:42:12] INFO [mysite:186] avoiddouble
|
||||
[24/Oct/2018 18:42:20] INFO [mysite:186] hi
|
||||
[24/Oct/2018 18:56:30] INFO [mysite:158] <QuerySet [<Tag: bamberg>, <Tag: test>]>
|
||||
[24/Oct/2018 18:56:30] INFO [mysite:161] <QuerySet []>
|
||||
[24/Oct/2018 18:56:30] INFO [mysite:161] <QuerySet [<Post: Third one>, <Post: first post>, <Post: second bla>]>
|
||||
[24/Oct/2018 18:56:45] INFO [mysite:190] None
|
||||
[24/Oct/2018 18:56:49] INFO [mysite:190] bamberg
|
||||
[24/Oct/2018 18:57:29] INFO [mysite:189] bamberg
|
||||
[24/Oct/2018 19:00:30] INFO [mysite:189] None
|
||||
[24/Oct/2018 19:00:30] INFO [mysite:191] <QuerySet []>
|
||||
[24/Oct/2018 19:00:33] INFO [mysite:189] hi
|
||||
[24/Oct/2018 19:00:33] INFO [mysite:191] <QuerySet [<Post: second bla>, <Post: Third one>]>
|
||||
[24/Oct/2018 19:00:38] INFO [mysite:189] bamberg
|
||||
[24/Oct/2018 19:00:38] INFO [mysite:191] <QuerySet []>
|
||||
[24/Oct/2018 19:00:54] INFO [mysite:189] bamberg
|
||||
[24/Oct/2018 19:00:54] INFO [mysite:191] <QuerySet []>
|
||||
[24/Oct/2018 19:01:16] INFO [mysite:189] test
|
||||
[24/Oct/2018 19:01:16] INFO [mysite:191] <QuerySet [<Post: second bla>, <Post: first post>, <Post: Third one>]>
|
||||
[24/Oct/2018 19:01:20] INFO [mysite:189] third
|
||||
[24/Oct/2018 19:01:20] INFO [mysite:191] <QuerySet [<Post: Third one>]>
|
||||
[24/Oct/2018 19:01:35] INFO [mysite:189] None
|
||||
[24/Oct/2018 19:01:35] INFO [mysite:191] <QuerySet []>
|
||||
[24/Oct/2018 19:01:40] INFO [mysite:189] bamberg
|
||||
[24/Oct/2018 19:01:40] INFO [mysite:191] <QuerySet []>
|
||||
[24/Oct/2018 19:03:03] INFO [mysite:189] None
|
||||
[24/Oct/2018 19:03:03] INFO [mysite:191] <QuerySet []>
|
||||
[24/Oct/2018 19:03:08] INFO [mysite:189] bamberg
|
||||
[24/Oct/2018 19:03:08] INFO [mysite:191] <QuerySet []>
|
||||
[24/Oct/2018 19:03:28] INFO [mysite:189] bamberg
|
||||
[24/Oct/2018 19:03:28] INFO [mysite:191] <QuerySet [<Post: Third one>]>
|
||||
[24/Oct/2018 19:03:45] INFO [mysite:189] bamberg
|
||||
[24/Oct/2018 19:03:45] INFO [mysite:191] <QuerySet [<Post: Third one>, <Post: here i go again>]>
|
||||
[25/Oct/2018 10:33:13] INFO [mysite:189] bamberg
|
||||
[25/Oct/2018 15:28:52] INFO [mysite:189] hi
|
||||
[25/Oct/2018 15:28:54] INFO [mysite:189]
|
||||
+98
-1
@@ -13,6 +13,7 @@ https://docs.djangoproject.com/en/2.0/ref/settings/
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import djcelery
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
@@ -43,9 +44,14 @@ INSTALLED_APPS = [
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.sites',
|
||||
'application',
|
||||
'taggit',
|
||||
'taggit_templatetags2',
|
||||
'djcelery',
|
||||
'kombu.transport.django',
|
||||
'sorl.thumbnail',
|
||||
'newsletter',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@@ -169,4 +175,95 @@ else:
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
'mysite.ldap_backend.LdapBackend',
|
||||
]
|
||||
print(" --- Live stage --- ")
|
||||
print(" --- Live stage --- ")
|
||||
|
||||
AUTH_PROFILE_MODULE = 'application.CustomUser'
|
||||
|
||||
#Log Configuration
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': True,
|
||||
'formatters': {
|
||||
'standard': {
|
||||
'format' : "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
|
||||
'datefmt' : "%d/%b/%Y %H:%M:%S"
|
||||
},
|
||||
},
|
||||
'handlers': {
|
||||
'null': {
|
||||
'level':'DEBUG',
|
||||
'class':'logging.NullHandler',
|
||||
},
|
||||
'logfile': {
|
||||
'level':'DEBUG',
|
||||
'class':'logging.handlers.RotatingFileHandler',
|
||||
'filename': os.path.join(BASE_DIR, 'log.txt'),
|
||||
'maxBytes': 50000,
|
||||
'backupCount': 2,
|
||||
'formatter': 'standard',
|
||||
},
|
||||
'console':{
|
||||
'level':'INFO',
|
||||
'class':'logging.StreamHandler',
|
||||
'formatter': 'standard'
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'django': {
|
||||
'handlers':['console'],
|
||||
'propagate': True,
|
||||
'level':'WARN',
|
||||
},
|
||||
'django.db.backends': {
|
||||
'handlers': ['console'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
'mysite': {
|
||||
'handlers': ['console', 'logfile'],
|
||||
'level': 'DEBUG',
|
||||
'formatter': 'standard'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if DEBUG:
|
||||
INTERNAL_IPS = ('127.0.0.1', 'localhost',)
|
||||
MIDDLEWARE += (
|
||||
'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||
)
|
||||
|
||||
INSTALLED_APPS += (
|
||||
'debug_toolbar',
|
||||
)
|
||||
|
||||
DEBUG_TOOLBAR_PANELS = [
|
||||
'debug_toolbar.panels.versions.VersionsPanel',
|
||||
'debug_toolbar.panels.timer.TimerPanel',
|
||||
'debug_toolbar.panels.settings.SettingsPanel',
|
||||
'debug_toolbar.panels.headers.HeadersPanel',
|
||||
'debug_toolbar.panels.request.RequestPanel',
|
||||
'debug_toolbar.panels.sql.SQLPanel',
|
||||
'debug_toolbar.panels.staticfiles.StaticFilesPanel',
|
||||
'debug_toolbar.panels.templates.TemplatesPanel',
|
||||
'debug_toolbar.panels.cache.CachePanel',
|
||||
'debug_toolbar.panels.signals.SignalsPanel',
|
||||
'debug_toolbar.panels.logging.LoggingPanel',
|
||||
'debug_toolbar.panels.redirects.RedirectsPanel',
|
||||
]
|
||||
|
||||
DEBUG_TOOLBAR_CONFIG = {
|
||||
'INTERCEPT_REDIRECTS': False,
|
||||
}
|
||||
|
||||
# Celery settings
|
||||
BROKER_URL = 'django://'
|
||||
CELERY_ACCEPT_CONTENT = ['json']
|
||||
CELERY_TASK_SERIALIZER = 'json'
|
||||
CELERY_RESULT_SERIALIZER = 'json'
|
||||
CELERY_RESULT_BACKEND = 'djcelery.backends.database:DatabaseBackend'
|
||||
CELERYBEAT_SCHEDULER = "djcelery.schedulers.DatabaseScheduler"
|
||||
djcelery.setup_loader()
|
||||
|
||||
SITE_ID = 1
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from celery.__main__ import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from celery.__main__ import _compat_beat
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(_compat_beat())
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from celery.__main__ import _compat_worker
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(_compat_worker())
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from celery.__main__ import _compat_multi
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(_compat_multi())
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'python-card-me==0.9.3','console_scripts','change_tz'
|
||||
__requires__ = 'python-card-me==0.9.3'
|
||||
import re
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(
|
||||
load_entry_point('python-card-me==0.9.3', 'console_scripts', 'change_tz')()
|
||||
)
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from chardet.cli.chardetect import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from ZODB.FileStorage.fsdump import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from ZODB.scripts.fsoids import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from ZODB.scripts.fsrefs import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from ZODB.scripts.fstail import Main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(Main())
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'python-card-me==0.9.3','console_scripts','ics_diff'
|
||||
__requires__ = 'python-card-me==0.9.3'
|
||||
import re
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(
|
||||
load_entry_point('python-card-me==0.9.3', 'console_scripts', 'ics_diff')()
|
||||
)
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from ZODB.scripts.repozo import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'ZEO==5.2.0','console_scripts','runzeo'
|
||||
__requires__ = 'ZEO==5.2.0'
|
||||
import re
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(
|
||||
load_entry_point('ZEO==5.2.0', 'console_scripts', 'runzeo')()
|
||||
)
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from sqlparse.__main__ import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
from surlex import Surlex
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
|
||||
def main():
|
||||
parser = OptionParser()
|
||||
parser.set_usage('surlex2regex.py <surlex>')
|
||||
if len(sys.argv) == 1:
|
||||
argv = ['-h']
|
||||
else:
|
||||
argv = sys.argv[1:]
|
||||
options, args = parser.parse_args(argv)
|
||||
print (Surlex(args[0]).translate())
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from ZConfig.validator import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from ZConfig.schema2html import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'zdaemon==4.2.0','console_scripts','zdaemon'
|
||||
__requires__ = 'zdaemon==4.2.0'
|
||||
import re
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(
|
||||
load_entry_point('zdaemon==4.2.0', 'console_scripts', 'zdaemon')()
|
||||
)
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'ZEO==5.2.0','console_scripts','zeo-nagios'
|
||||
__requires__ = 'ZEO==5.2.0'
|
||||
import re
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(
|
||||
load_entry_point('ZEO==5.2.0', 'console_scripts', 'zeo-nagios')()
|
||||
)
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'ZEO==5.2.0','console_scripts','zeoctl'
|
||||
__requires__ = 'ZEO==5.2.0'
|
||||
import re
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(
|
||||
load_entry_point('ZEO==5.2.0', 'console_scripts', 'zeoctl')()
|
||||
)
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/Users/Esthi/thesis_ek/thesisenv/bin/python3
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'ZEO==5.2.0','console_scripts','zeopack'
|
||||
__requires__ = 'ZEO==5.2.0'
|
||||
import re
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(
|
||||
load_entry_point('ZEO==5.2.0', 'console_scripts', 'zeopack')()
|
||||
)
|
||||
@@ -0,0 +1,156 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2001, 2002 Zope Foundation and Contributors.
|
||||
All Rights Reserved.
|
||||
|
||||
This software is subject to the provisions of the Zope Public License,
|
||||
Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CPERSISTENCE_H
|
||||
#define CPERSISTENCE_H
|
||||
|
||||
#include "_compat.h"
|
||||
#include "bytesobject.h"
|
||||
|
||||
#include "ring.h"
|
||||
|
||||
#define CACHE_HEAD \
|
||||
PyObject_HEAD \
|
||||
CPersistentRing ring_home; \
|
||||
int non_ghost_count; \
|
||||
Py_ssize_t total_estimated_size;
|
||||
|
||||
struct ccobject_head_struct;
|
||||
|
||||
typedef struct ccobject_head_struct PerCache;
|
||||
|
||||
/* How big is a persistent object?
|
||||
|
||||
12 PyGC_Head is two pointers and an int
|
||||
8 PyObject_HEAD is an int and a pointer
|
||||
|
||||
12 jar, oid, cache pointers
|
||||
8 ring struct
|
||||
8 serialno
|
||||
4 state + extra
|
||||
4 size info
|
||||
|
||||
(56) so far
|
||||
|
||||
4 dict ptr
|
||||
4 weaklist ptr
|
||||
-------------------------
|
||||
68 only need 62, but obmalloc rounds up to multiple of eight
|
||||
|
||||
Even a ghost requires 64 bytes. It's possible to make a persistent
|
||||
instance with slots and no dict, which changes the storage needed.
|
||||
|
||||
*/
|
||||
|
||||
#define cPersistent_HEAD \
|
||||
PyObject_HEAD \
|
||||
PyObject *jar; \
|
||||
PyObject *oid; \
|
||||
PerCache *cache; \
|
||||
CPersistentRing ring; \
|
||||
char serial[8]; \
|
||||
signed state:8; \
|
||||
unsigned estimated_size:24;
|
||||
|
||||
/* We recently added estimated_size. We originally added it as a new
|
||||
unsigned long field after a signed char state field and a
|
||||
3-character reserved field. This didn't work because there
|
||||
are packages in the wild that have their own copies of cPersistence.h
|
||||
that didn't see the update.
|
||||
|
||||
To get around this, we used the reserved space by making
|
||||
estimated_size a 24-bit bit field in the space occupied by the old
|
||||
3-character reserved field. To fit in 24 bits, we made the units
|
||||
of estimated_size 64-character blocks. This allows is to handle up
|
||||
to a GB. We should never see that, but to be paranoid, we also
|
||||
truncate sizes greater than 1GB. We also set the minimum size to
|
||||
64 bytes.
|
||||
|
||||
We use the _estimated_size_in_24_bits and _estimated_size_in_bytes
|
||||
macros both to avoid repetition and to make intent a little clearer.
|
||||
*/
|
||||
#define _estimated_size_in_24_bits(I) ((I) > 1073741696 ? 16777215 : (I)/64+1)
|
||||
#define _estimated_size_in_bytes(I) ((I)*64)
|
||||
|
||||
#define cPersistent_GHOST_STATE -1
|
||||
#define cPersistent_UPTODATE_STATE 0
|
||||
#define cPersistent_CHANGED_STATE 1
|
||||
#define cPersistent_STICKY_STATE 2
|
||||
|
||||
typedef struct {
|
||||
cPersistent_HEAD
|
||||
} cPersistentObject;
|
||||
|
||||
typedef void (*percachedelfunc)(PerCache *, PyObject *);
|
||||
|
||||
typedef struct {
|
||||
PyTypeObject *pertype;
|
||||
getattrofunc getattro;
|
||||
setattrofunc setattro;
|
||||
int (*changed)(cPersistentObject*);
|
||||
void (*accessed)(cPersistentObject*);
|
||||
void (*ghostify)(cPersistentObject*);
|
||||
int (*setstate)(PyObject*);
|
||||
percachedelfunc percachedel;
|
||||
int (*readCurrent)(cPersistentObject*);
|
||||
} cPersistenceCAPIstruct;
|
||||
|
||||
#define cPersistenceType cPersistenceCAPI->pertype
|
||||
|
||||
#ifndef DONT_USE_CPERSISTENCECAPI
|
||||
static cPersistenceCAPIstruct *cPersistenceCAPI;
|
||||
#endif
|
||||
|
||||
#define cPersistanceModuleName "cPersistence"
|
||||
|
||||
#define PER_TypeCheck(O) PyObject_TypeCheck((O), cPersistenceCAPI->pertype)
|
||||
|
||||
#define PER_USE_OR_RETURN(O,R) {if((O)->state==cPersistent_GHOST_STATE && cPersistenceCAPI->setstate((PyObject*)(O)) < 0) return (R); else if ((O)->state==cPersistent_UPTODATE_STATE) (O)->state=cPersistent_STICKY_STATE;}
|
||||
|
||||
#define PER_CHANGED(O) (cPersistenceCAPI->changed((cPersistentObject*)(O)))
|
||||
|
||||
#define PER_READCURRENT(O, E) \
|
||||
if (cPersistenceCAPI->readCurrent((cPersistentObject*)(O)) < 0) { E; }
|
||||
|
||||
#define PER_GHOSTIFY(O) (cPersistenceCAPI->ghostify((cPersistentObject*)(O)))
|
||||
|
||||
/* If the object is sticky, make it non-sticky, so that it can be ghostified.
|
||||
The value is not meaningful
|
||||
*/
|
||||
#define PER_ALLOW_DEACTIVATION(O) ((O)->state==cPersistent_STICKY_STATE && ((O)->state=cPersistent_UPTODATE_STATE))
|
||||
|
||||
#define PER_PREVENT_DEACTIVATION(O) ((O)->state==cPersistent_UPTODATE_STATE && ((O)->state=cPersistent_STICKY_STATE))
|
||||
|
||||
/*
|
||||
Make a persistent object usable from C by:
|
||||
|
||||
- Making sure it is not a ghost
|
||||
|
||||
- Making it sticky.
|
||||
|
||||
IMPORTANT: If you call this and don't call PER_ALLOW_DEACTIVATION,
|
||||
your object will not be ghostified.
|
||||
|
||||
PER_USE returns a 1 on success and 0 failure, where failure means
|
||||
error.
|
||||
*/
|
||||
#define PER_USE(O) \
|
||||
(((O)->state != cPersistent_GHOST_STATE \
|
||||
|| (cPersistenceCAPI->setstate((PyObject*)(O)) >= 0)) \
|
||||
? (((O)->state==cPersistent_UPTODATE_STATE) \
|
||||
? ((O)->state=cPersistent_STICKY_STATE) : 1) : 0)
|
||||
|
||||
#define PER_ACCESSED(O) (cPersistenceCAPI->accessed((cPersistentObject*)(O)))
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,66 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2003 Zope Foundation and Contributors.
|
||||
All Rights Reserved.
|
||||
|
||||
This software is subject to the provisions of the Zope Public License,
|
||||
Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
/* Support routines for the doubly-linked list of cached objects.
|
||||
|
||||
The cache stores a headed, doubly-linked, circular list of persistent
|
||||
objects, with space for the pointers allocated in the objects themselves.
|
||||
The cache stores the distinguished head of the list, which is not a valid
|
||||
persistent object. The other list members are non-ghost persistent
|
||||
objects, linked in LRU (least-recently used) order.
|
||||
|
||||
The r_next pointers traverse the ring starting with the least recently used
|
||||
object. The r_prev pointers traverse the ring starting with the most
|
||||
recently used object.
|
||||
|
||||
Obscure: While each object is pointed at twice by list pointers (once by
|
||||
its predecessor's r_next, again by its successor's r_prev), the refcount
|
||||
on the object is bumped only by 1. This leads to some possibly surprising
|
||||
sequences of incref and decref code. Note that since the refcount is
|
||||
bumped at least once, the list does hold a strong reference to each
|
||||
object in it.
|
||||
*/
|
||||
|
||||
typedef struct CPersistentRing_struct
|
||||
{
|
||||
struct CPersistentRing_struct *r_prev;
|
||||
struct CPersistentRing_struct *r_next;
|
||||
} CPersistentRing;
|
||||
|
||||
/* The list operations here take constant time independent of the
|
||||
* number of objects in the list:
|
||||
*/
|
||||
|
||||
/* Add elt as the most recently used object. elt must not already be
|
||||
* in the list, although this isn't checked.
|
||||
*/
|
||||
void ring_add(CPersistentRing *ring, CPersistentRing *elt);
|
||||
|
||||
/* Remove elt from the list. elt must already be in the list, although
|
||||
* this isn't checked.
|
||||
*/
|
||||
void ring_del(CPersistentRing *elt);
|
||||
|
||||
/* elt must already be in the list, although this isn't checked. It's
|
||||
* unlinked from its current position, and relinked into the list as the
|
||||
* most recently used object (which is arguably the tail of the list
|
||||
* instead of the head -- but the name of this function could be argued
|
||||
* either way). This is equivalent to
|
||||
*
|
||||
* ring_del(elt);
|
||||
* ring_add(ring, elt);
|
||||
*
|
||||
* but may be a little quicker.
|
||||
*/
|
||||
void ring_move_to_head(CPersistentRing *ring, CPersistentRing *elt);
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef _proxy_H_
|
||||
#define _proxy_H_ 1
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *proxy_object;
|
||||
} ProxyObject;
|
||||
|
||||
#define Proxy_GET_OBJECT(ob) (((ProxyObject *)(ob))->proxy_object)
|
||||
|
||||
typedef struct {
|
||||
PyTypeObject *proxytype;
|
||||
int (*check)(PyObject *obj);
|
||||
PyObject *(*create)(PyObject *obj);
|
||||
PyObject *(*getobject)(PyObject *proxy);
|
||||
} ProxyInterface;
|
||||
|
||||
#ifndef PROXY_MODULE
|
||||
|
||||
/* These are only defined in the public interface, and are not
|
||||
* available within the module implementation. There we use the
|
||||
* classic Python/C API only.
|
||||
*/
|
||||
|
||||
static ProxyInterface *_proxy_api = NULL;
|
||||
|
||||
static int
|
||||
Proxy_Import(void)
|
||||
{
|
||||
if (_proxy_api == NULL) {
|
||||
PyObject *m = PyImport_ImportModule("zope.proxy");
|
||||
if (m != NULL) {
|
||||
PyObject *tmp = PyObject_GetAttrString(m, "_CAPI");
|
||||
if (tmp != NULL) {
|
||||
#if PY_VERSION_HEX < 0x02070000
|
||||
if (PyCObject_Check(tmp))
|
||||
_proxy_api = (ProxyInterface *)
|
||||
PyCObject_AsVoidPtr(tmp);
|
||||
#else
|
||||
if (PyCapsule_CheckExact(tmp))
|
||||
_proxy_api = (ProxyInterface *)
|
||||
PyCapsule_GetPointer(tmp, NULL);
|
||||
#endif
|
||||
Py_DECREF(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (_proxy_api == NULL) ? -1 : 0;
|
||||
}
|
||||
|
||||
#define ProxyType (*_proxy_api->proxytype)
|
||||
#define Proxy_Check(obj) (_proxy_api->check((obj)))
|
||||
#define Proxy_CheckExact(obj) ((obj)->ob_type == ProxyType)
|
||||
#define Proxy_New(obj) (_proxy_api->create((obj)))
|
||||
#define Proxy_GetObject(proxy) (_proxy_api->getobject((proxy)))
|
||||
|
||||
#endif /* PROXY_MODULE */
|
||||
|
||||
#endif /* _proxy_H_ */
|
||||
@@ -0,0 +1,697 @@
|
||||
Metadata-Version: 1.1
|
||||
Name: Acquisition
|
||||
Version: 4.5
|
||||
Summary: Acquisition is a mechanism that allows objects to obtain attributes from the containment hierarchy they're in.
|
||||
Home-page: https://github.com/zopefoundation/Acquisition
|
||||
Author: Zope Foundation and Contributors
|
||||
Author-email: zope-dev@zope.org
|
||||
License: ZPL 2.1
|
||||
Description: Environmental Acquisiton
|
||||
========================
|
||||
|
||||
This package implements "environmental acquisiton" for Python, as
|
||||
proposed in the OOPSLA96_ paper by Joseph Gil and David H. Lorenz:
|
||||
|
||||
We propose a new programming paradigm, environmental acquisition in
|
||||
the context of object aggregation, in which objects acquire
|
||||
behaviour from their current containers at runtime. The key idea is
|
||||
that the behaviour of a component may depend upon its enclosing
|
||||
composite(s). In particular, we propose a form of feature sharing in
|
||||
which an object "inherits" features from the classes of objects in
|
||||
its environment. By examining the declaration of classes, it is
|
||||
possible to determine which kinds of classes may contain a
|
||||
component, and which components must be contained in a given kind of
|
||||
composite. These relationships are the basis for language constructs
|
||||
that supports acquisition.
|
||||
|
||||
.. _OOPSLA96: http://www.cs.virginia.edu/~lorenz/papers/oopsla96/>`_:
|
||||
|
||||
.. contents::
|
||||
|
||||
Introductory Example
|
||||
--------------------
|
||||
|
||||
Zope implements acquisition with "Extension Class" mix-in classes. To
|
||||
use acquisition your classes must inherit from an acquisition base
|
||||
class. For example::
|
||||
|
||||
>>> import ExtensionClass, Acquisition
|
||||
|
||||
>>> class C(ExtensionClass.Base):
|
||||
... color = 'red'
|
||||
|
||||
>>> class A(Acquisition.Implicit):
|
||||
... def report(self):
|
||||
... print(self.color)
|
||||
...
|
||||
>>> a = A()
|
||||
>>> c = C()
|
||||
>>> c.a = a
|
||||
|
||||
>>> c.a.report()
|
||||
red
|
||||
|
||||
>>> d = C()
|
||||
>>> d.color = 'green'
|
||||
>>> d.a = a
|
||||
|
||||
>>> d.a.report()
|
||||
green
|
||||
|
||||
>>> try:
|
||||
... a.report()
|
||||
... except AttributeError:
|
||||
... pass
|
||||
... else:
|
||||
... raise AssertionError('AttributeError not raised.')
|
||||
|
||||
The class ``A`` inherits acquisition behavior from
|
||||
``Acquisition.Implicit``. The object, ``a``, "has" the color of
|
||||
objects ``c`` and d when it is accessed through them, but it has no
|
||||
color by itself. The object ``a`` obtains attributes from its
|
||||
environment, where its environment is defined by the access path used
|
||||
to reach ``a``.
|
||||
|
||||
Acquisition Wrappers
|
||||
--------------------
|
||||
|
||||
When an object that supports acquisition is accessed through an
|
||||
extension class instance, a special object, called an acquisition
|
||||
wrapper, is returned. In the example above, the expression ``c.a``
|
||||
returns an acquisition wrapper that contains references to both ``c``
|
||||
and ``a``. It is this wrapper that performs attribute lookup in ``c``
|
||||
when an attribute cannot be found in ``a``.
|
||||
|
||||
Acquisition wrappers provide access to the wrapped objects through the
|
||||
attributes ``aq_parent``, ``aq_self``, ``aq_base``. Continue the
|
||||
example from above::
|
||||
|
||||
>>> c.a.aq_parent is c
|
||||
True
|
||||
>>> c.a.aq_self is a
|
||||
True
|
||||
|
||||
Explicit and Implicit Acquisition
|
||||
---------------------------------
|
||||
|
||||
Two styles of acquisition are supported: implicit and explicit
|
||||
acquisition.
|
||||
|
||||
Implicit acquisition
|
||||
--------------------
|
||||
|
||||
Implicit acquisition is so named because it searches for attributes
|
||||
from the environment automatically whenever an attribute cannot be
|
||||
obtained directly from an object or through inheritance.
|
||||
|
||||
An attribute can be implicitly acquired if its name does not begin
|
||||
with an underscore.
|
||||
|
||||
To support implicit acquisition, your class should inherit from the
|
||||
mix-in class ``Acquisition.Implicit``.
|
||||
|
||||
Explicit Acquisition
|
||||
--------------------
|
||||
|
||||
When explicit acquisition is used, attributes are not automatically
|
||||
obtained from the environment. Instead, the method aq_acquire must be
|
||||
used. For example::
|
||||
|
||||
>>> print(c.a.aq_acquire('color'))
|
||||
red
|
||||
|
||||
To support explicit acquisition, your class should inherit from the
|
||||
mix-in class ``Acquisition.Explicit``.
|
||||
|
||||
Controlling Acquisition
|
||||
-----------------------
|
||||
|
||||
A class (or instance) can provide attribute by attribute control over
|
||||
acquisition. Your should subclass from ``Acquisition.Explicit``, and set
|
||||
all attributes that should be acquired to the special value
|
||||
``Acquisition.Acquired``. Setting an attribute to this value also allows
|
||||
inherited attributes to be overridden with acquired ones. For example::
|
||||
|
||||
>>> class C(Acquisition.Explicit):
|
||||
... id = 1
|
||||
... secret = 2
|
||||
... color = Acquisition.Acquired
|
||||
... __roles__ = Acquisition.Acquired
|
||||
|
||||
The only attributes that are automatically acquired from containing
|
||||
objects are color, and ``__roles__``. Note that the ``__roles__``
|
||||
attribute is acquired even though its name begins with an
|
||||
underscore. In fact, the special ``Acquisition.Acquired`` value can be
|
||||
used in ``Acquisition.Implicit`` objects to implicitly acquire
|
||||
selected objects that smell like private objects.
|
||||
|
||||
Sometimes, you want to dynamically make an implicitly acquiring object
|
||||
acquire explicitly. You can do this by getting the object's
|
||||
aq_explicit attribute. This attribute provides the object with an
|
||||
explicit wrapper that replaces the original implicit wrapper.
|
||||
|
||||
Filtered Acquisition
|
||||
--------------------
|
||||
|
||||
The acquisition method, ``aq_acquire``, accepts two optional
|
||||
arguments. The first of the additional arguments is a "filtering"
|
||||
function that is used when considering whether to acquire an
|
||||
object. The second of the additional arguments is an object that is
|
||||
passed as extra data when calling the filtering function and which
|
||||
defaults to ``None``. The filter function is called with five
|
||||
arguments:
|
||||
|
||||
* The object that the aq_acquire method was called on,
|
||||
|
||||
* The object where an object was found,
|
||||
|
||||
* The name of the object, as passed to aq_acquire,
|
||||
|
||||
* The object found, and
|
||||
|
||||
* The extra data passed to aq_acquire.
|
||||
|
||||
If the filter returns a true object that the object found is returned,
|
||||
otherwise, the acquisition search continues.
|
||||
|
||||
Here's an example::
|
||||
|
||||
>>> from Acquisition import Explicit
|
||||
|
||||
>>> class HandyForTesting(object):
|
||||
... def __init__(self, name):
|
||||
... self.name = name
|
||||
... def __str__(self):
|
||||
... return "%s(%s)" % (self.name, self.__class__.__name__)
|
||||
... __repr__=__str__
|
||||
...
|
||||
>>> class E(Explicit, HandyForTesting): pass
|
||||
...
|
||||
>>> class Nice(HandyForTesting):
|
||||
... isNice = 1
|
||||
... def __str__(self):
|
||||
... return HandyForTesting.__str__(self)+' and I am nice!'
|
||||
... __repr__ = __str__
|
||||
...
|
||||
>>> a = E('a')
|
||||
>>> a.b = E('b')
|
||||
>>> a.b.c = E('c')
|
||||
>>> a.p = Nice('spam')
|
||||
>>> a.b.p = E('p')
|
||||
|
||||
>>> def find_nice(self, ancestor, name, object, extra):
|
||||
... return hasattr(object,'isNice') and object.isNice
|
||||
|
||||
>>> print(a.b.c.aq_acquire('p', find_nice))
|
||||
spam(Nice) and I am nice!
|
||||
|
||||
The filtered acquisition in the last line skips over the first
|
||||
attribute it finds with the name ``p``, because the attribute doesn't
|
||||
satisfy the condition given in the filter.
|
||||
|
||||
Filtered acquisition is rarely used in Zope.
|
||||
|
||||
Acquiring from Context
|
||||
----------------------
|
||||
|
||||
Normally acquisition allows objects to acquire data from their
|
||||
containers. However an object can acquire from objects that aren't its
|
||||
containers.
|
||||
|
||||
Most of the examples we've seen so far show establishing of an
|
||||
acquisition context using getattr semantics. For example, ``a.b`` is a
|
||||
reference to ``b`` in the context of ``a``.
|
||||
|
||||
You can also manually set acquisition context using the ``__of__``
|
||||
method. For example::
|
||||
|
||||
>>> from Acquisition import Implicit
|
||||
>>> class C(Implicit): pass
|
||||
...
|
||||
>>> a = C()
|
||||
>>> b = C()
|
||||
>>> a.color = "red"
|
||||
>>> print(b.__of__(a).color)
|
||||
red
|
||||
|
||||
In this case, ``a`` does not contain ``b``, but it is put in ``b``'s
|
||||
context using the ``__of__`` method.
|
||||
|
||||
Here's another subtler example that shows how you can construct an
|
||||
acquisition context that includes non-container objects::
|
||||
|
||||
>>> from Acquisition import Implicit
|
||||
|
||||
>>> class C(Implicit):
|
||||
... def __init__(self, name):
|
||||
... self.name = name
|
||||
|
||||
>>> a = C("a")
|
||||
>>> a.b = C("b")
|
||||
>>> a.b.color = "red"
|
||||
>>> a.x = C("x")
|
||||
|
||||
>>> print(a.b.x.color)
|
||||
red
|
||||
|
||||
Even though ``b`` does not contain ``x``, ``x`` can acquire the color
|
||||
attribute from ``b``. This works because in this case, ``x`` is accessed
|
||||
in the context of ``b`` even though it is not contained by ``b``.
|
||||
|
||||
Here acquisition context is defined by the objects used to access
|
||||
another object.
|
||||
|
||||
Containment Before Context
|
||||
--------------------------
|
||||
|
||||
If in the example above suppose both a and b have an color attribute::
|
||||
|
||||
>>> a = C("a")
|
||||
>>> a.color = "green"
|
||||
>>> a.b = C("b")
|
||||
>>> a.b.color = "red"
|
||||
>>> a.x = C("x")
|
||||
|
||||
>>> print(a.b.x.color)
|
||||
green
|
||||
|
||||
Why does ``a.b.x.color`` acquire color from ``a`` and not from ``b``?
|
||||
The answer is that an object acquires from its containers before
|
||||
non-containers in its context.
|
||||
|
||||
To see why consider this example in terms of expressions using the
|
||||
``__of__`` method::
|
||||
|
||||
a.x -> x.__of__(a)
|
||||
|
||||
a.b -> b.__of__(a)
|
||||
|
||||
a.b.x -> x.__of__(a).__of__(b.__of__(a))
|
||||
|
||||
Keep in mind that attribute lookup in a wrapper is done by trying to
|
||||
look up the attribute in the wrapped object first and then in the
|
||||
parent object. So in the expressions above proceeds from left to
|
||||
right.
|
||||
|
||||
The upshot of these rules is that attributes are looked up by
|
||||
containment before context.
|
||||
|
||||
This rule holds true also for more complex examples. For example,
|
||||
``a.b.c.d.e.f.g.attribute`` would search for attribute in ``g`` and
|
||||
all its containers first. (Containers are searched in order from the
|
||||
innermost parent to the outermost container.) If the attribute is not
|
||||
found in ``g`` or any of its containers, then the search moves to
|
||||
``f`` and all its containers, and so on.
|
||||
|
||||
Additional Attributes and Methods
|
||||
---------------------------------
|
||||
|
||||
You can use the special method ``aq_inner`` to access an object
|
||||
wrapped only by containment. So in the example above,
|
||||
``a.b.x.aq_inner`` is equivalent to ``a.x``.
|
||||
|
||||
You can find out the acquisition context of an object using the
|
||||
aq_chain method like so:
|
||||
|
||||
>>> [obj.name for obj in a.b.x.aq_chain]
|
||||
['x', 'b', 'a']
|
||||
|
||||
You can find out if an object is in the containment context of another
|
||||
object using the ``aq_inContextOf`` method. For example:
|
||||
|
||||
>>> a.b.aq_inContextOf(a)
|
||||
True
|
||||
|
||||
.. Note: as of this writing the aq_inContextOf examples don't work the
|
||||
way they should be working. According to Jim, this is because
|
||||
aq_inContextOf works by comparing object pointer addresses, which
|
||||
(because they are actually different wrapper objects) doesn't give
|
||||
you the expected results. He acknowledges that this behavior is
|
||||
controversial, and says that there is a collector entry to change
|
||||
it so that you would get the answer you expect in the above. (We
|
||||
just need to get to it).
|
||||
|
||||
Acquisition Module Functions
|
||||
----------------------------
|
||||
|
||||
In addition to using acquisition attributes and methods directly on
|
||||
objects you can use similar functions defined in the ``Acquisition``
|
||||
module. These functions have the advantage that you don't need to
|
||||
check to make sure that the object has the method or attribute before
|
||||
calling it.
|
||||
|
||||
``aq_acquire(object, name [, filter, extra, explicit, default, containment])``
|
||||
Acquires an object with the given name.
|
||||
|
||||
This function can be used to explictly acquire when using explicit
|
||||
acquisition and to acquire names that wouldn't normally be
|
||||
acquired.
|
||||
|
||||
The function accepts a number of optional arguments:
|
||||
|
||||
``filter``
|
||||
A callable filter object that is used to decide if an object
|
||||
should be acquired.
|
||||
|
||||
The filter is called with five arguments:
|
||||
|
||||
* The object that the aq_acquire method was called on,
|
||||
|
||||
* The object where an object was found,
|
||||
|
||||
* The name of the object, as passed to aq_acquire,
|
||||
|
||||
* The object found, and
|
||||
|
||||
* The extra argument passed to aq_acquire.
|
||||
|
||||
If the filter returns a true object that the object found is
|
||||
returned, otherwise, the acquisition search continues.
|
||||
|
||||
``extra``
|
||||
Extra data to be passed as the last argument to the filter.
|
||||
|
||||
``explicit``
|
||||
A flag (boolean value) indicating whether explicit acquisition
|
||||
should be used. The default value is true. If the flag is
|
||||
true, then acquisition will proceed regardless of whether
|
||||
wrappers encountered in the search of the acquisition
|
||||
hierarchy are explicit or implicit wrappers. If the flag is
|
||||
false, then parents of explicit wrappers are not searched.
|
||||
|
||||
This argument is useful if you want to apply a filter without
|
||||
overriding explicit wrappers.
|
||||
|
||||
``default``
|
||||
A default value to return if no value can be acquired.
|
||||
|
||||
``containment``
|
||||
A flag indicating whether the search should be limited to the
|
||||
containment hierarchy.
|
||||
|
||||
In addition, arguments can be provided as keywords.
|
||||
|
||||
``aq_base(object)``
|
||||
Return the object with all wrapping removed.
|
||||
|
||||
``aq_chain(object [, containment])``
|
||||
Return a list containing the object and it's acquisition
|
||||
parents. The optional argument, containment, controls whether the
|
||||
containment or access hierarchy is used.
|
||||
|
||||
``aq_get(object, name [, default, containment])``
|
||||
Acquire an attribute, name. A default value can be provided, as
|
||||
can a flag that limits search to the containment hierarchy.
|
||||
|
||||
``aq_inner(object)``
|
||||
Return the object with all but the innermost layer of wrapping
|
||||
removed.
|
||||
|
||||
``aq_parent(object)``
|
||||
Return the acquisition parent of the object or None if the object
|
||||
is unwrapped.
|
||||
|
||||
``aq_self(object)``
|
||||
Return the object with one layer of wrapping removed, unless the
|
||||
object is unwrapped, in which case the object is returned.
|
||||
|
||||
In most cases it is more convenient to use these module functions
|
||||
instead of the acquisition attributes and methods directly.
|
||||
|
||||
Acquisition and Methods
|
||||
-----------------------
|
||||
|
||||
Python methods of objects that support acquisition can use acquired
|
||||
attributes. When a Python method is called on an object that is
|
||||
wrapped by an acquisition wrapper, the wrapper is passed to the method
|
||||
as the first argument. This rule also applies to user-defined method
|
||||
types and to C methods defined in pure mix-in classes.
|
||||
|
||||
Unfortunately, C methods defined in extension base classes that define
|
||||
their own data structures, cannot use aquired attributes at this
|
||||
time. This is because wrapper objects do not conform to the data
|
||||
structures expected by these methods. In practice, you will seldom
|
||||
find this a problem.
|
||||
|
||||
Conclusion
|
||||
----------
|
||||
|
||||
Acquisition provides a powerful way to dynamically share information
|
||||
between objects. Zope 2 uses acquisition for a number of its key
|
||||
features including security, object publishing, and DTML variable
|
||||
lookup. Acquisition also provides an elegant solution to the problem
|
||||
of circular references for many classes of problems. While acquisition
|
||||
is powerful, you should take care when using acquisition in your
|
||||
applications. The details can get complex, especially with the
|
||||
differences between acquiring from context and acquiring from
|
||||
containment.
|
||||
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
4.5 (2018-10-05)
|
||||
----------------
|
||||
|
||||
- Avoid deprecation warnings by using current API.
|
||||
|
||||
- Add support for Python 3.7.
|
||||
|
||||
4.4.4 (2017-11-24)
|
||||
------------------
|
||||
|
||||
- Add Appveyor configuration to automate building Windows eggs.
|
||||
|
||||
4.4.3 (2017-11-23)
|
||||
------------------
|
||||
|
||||
- Fix the extremely rare potential for a crash when the C extensions
|
||||
are in use. See `issue 21 <https://github.com/zopefoundation/Acquisition/issues/21>`_.
|
||||
|
||||
4.4.2 (2017-05-12)
|
||||
------------------
|
||||
|
||||
- Fix C capsule name to fix import errors.
|
||||
|
||||
- Ensure our dependencies match our expactations about C extensions.
|
||||
|
||||
4.4.1 (2017-05-04)
|
||||
------------------
|
||||
|
||||
- Fix C code under Python 3.4, with missing Py_XSETREF.
|
||||
|
||||
4.4.0 (2017-05-04)
|
||||
------------------
|
||||
|
||||
- Enable the C extension under Python 3.
|
||||
|
||||
- Drop support for Python 3.3.
|
||||
|
||||
4.3.0 (2017-01-20)
|
||||
------------------
|
||||
|
||||
- Make tests compatible with ExtensionClass 4.2.0.
|
||||
|
||||
- Drop support for Python 2.6 and 3.2.
|
||||
|
||||
- Add support for Python 3.5 and 3.6.
|
||||
|
||||
4.2.2 (2015-05-19)
|
||||
------------------
|
||||
|
||||
- Make the pure-Python Acquirer objects cooperatively use the
|
||||
superclass ``__getattribute__`` method, like the C implementation.
|
||||
See https://github.com/zopefoundation/Acquisition/issues/7.
|
||||
|
||||
- The pure-Python implicit acquisition wrapper allows wrapped objects
|
||||
to use ``object.__getattribute__(self, name)``. This differs from
|
||||
the C implementation, but is important for compatibility with the
|
||||
pure-Python versions of libraries like ``persistent``. See
|
||||
https://github.com/zopefoundation/Acquisition/issues/9.
|
||||
|
||||
4.2.1 (2015-04-23)
|
||||
------------------
|
||||
|
||||
- Correct several dangling pointer uses in the C extension,
|
||||
potentially fixing a few interpreter crashes. See
|
||||
https://github.com/zopefoundation/Acquisition/issues/5.
|
||||
|
||||
4.2 (2015-04-04)
|
||||
----------------
|
||||
|
||||
- Add support for PyPy, PyPy3, and Python 3.2, 3.3, and 3.4.
|
||||
|
||||
4.1 (2014-12-18)
|
||||
----------------
|
||||
|
||||
- Bump dependency on ``ExtensionClass`` to match current release.
|
||||
|
||||
4.0.3 (2014-11-02)
|
||||
------------------
|
||||
|
||||
- Skip readme.rst tests when tests are run outside a source checkout.
|
||||
|
||||
4.0.2 (2014-11-02)
|
||||
------------------
|
||||
|
||||
- Include ``*.rst`` files in the release.
|
||||
|
||||
4.0.1 (2014-10-30)
|
||||
------------------
|
||||
|
||||
- Tolerate Unicode attribute names (ASCII only). LP #143358.
|
||||
|
||||
- Make module-level ``aq_acquire`` API respect the ``default`` parameter.
|
||||
LP #1387363.
|
||||
|
||||
- Don't raise an attribute error for ``__iter__`` if the fallback to
|
||||
``__getitem__`` succeeds. LP #1155760.
|
||||
|
||||
|
||||
4.0 (2013-02-24)
|
||||
----------------
|
||||
|
||||
- Added trove classifiers to project metadata.
|
||||
|
||||
4.0a1 (2011-12-13)
|
||||
------------------
|
||||
|
||||
- Raise `RuntimeError: Recursion detected in acquisition wrapper` if an object
|
||||
with a `__parent__` pointer points to a wrapper that in turn points to the
|
||||
original object.
|
||||
|
||||
- Prevent wrappers to be created while accessing `__parent__` on types derived
|
||||
from Explicit or Implicit base classes.
|
||||
|
||||
2.13.9 (2015-02-17)
|
||||
-------------------
|
||||
|
||||
- Tolerate Unicode attribute names (ASCII only). LP #143358.
|
||||
|
||||
- Make module-level ``aq_acquire`` API respect the ``default`` parameter.
|
||||
LP #1387363.
|
||||
|
||||
- Don't raise an attribute error for ``__iter__`` if the fallback to
|
||||
``__getitem__`` succeeds. LP #1155760.
|
||||
|
||||
2.13.8 (2011-06-11)
|
||||
-------------------
|
||||
|
||||
- Fixed a segfault on 64bit platforms when providing the `explicit` argument to
|
||||
the aq_acquire method of an Acquisition wrapper. Thx to LP #675064 for the
|
||||
hint to the solution. The code passed an int instead of a pointer into a
|
||||
function.
|
||||
|
||||
2.13.7 (2011-03-02)
|
||||
-------------------
|
||||
|
||||
- Fixed bug: When an object did not implement ``__unicode__``, calling
|
||||
``unicode(wrapped)`` was calling ``__str__`` with an unwrapped ``self``.
|
||||
|
||||
2.13.6 (2011-02-19)
|
||||
-------------------
|
||||
|
||||
- Add ``aq_explicit`` to ``IAcquisitionWrapper``.
|
||||
|
||||
- Fixed bug: ``unicode(wrapped)`` was not calling a ``__unicode__``
|
||||
method on wrapped objects.
|
||||
|
||||
2.13.5 (2010-09-29)
|
||||
-------------------
|
||||
|
||||
- Fixed unit tests that failed on 64bit Python on Windows machines.
|
||||
|
||||
2.13.4 (2010-08-31)
|
||||
-------------------
|
||||
|
||||
- LP 623665: Fixed typo in Acquisition.h.
|
||||
|
||||
2.13.3 (2010-04-19)
|
||||
-------------------
|
||||
|
||||
- Use the doctest module from the standard library and no longer depend on
|
||||
zope.testing.
|
||||
|
||||
2.13.2 (2010-04-04)
|
||||
-------------------
|
||||
|
||||
- Give both wrapper classes a ``__getnewargs__`` method, which causes the ZODB
|
||||
optimization to fail and create persistent references using the ``_p_oid``
|
||||
alone. This happens to be the persistent oid of the wrapped object. This lets
|
||||
these objects to be persisted correctly, even though they are passed to the
|
||||
ZODB in a wrapped state.
|
||||
|
||||
- Added failing tests for http://dev.plone.org/plone/ticket/10318. This shows
|
||||
an edge-case where AQ wrappers can be pickled using the specific combination
|
||||
of cPickle, pickle protocol one and a custom Pickler class with an
|
||||
``inst_persistent_id`` hook. Unfortunately this is the exact combination used
|
||||
by ZODB3.
|
||||
|
||||
2.13.1 (2010-02-23)
|
||||
-------------------
|
||||
|
||||
- Update to include ExtensionClass 2.13.0.
|
||||
|
||||
- Fix the ``tp_name`` of the ImplicitAcquisitionWrapper and
|
||||
ExplicitAcquisitionWrapper to match their Python visible names and thus have
|
||||
a correct ``__name__``.
|
||||
|
||||
- Expand the ``tp_name`` of our extension types to hold the fully qualified
|
||||
name. This ensures classes have their ``__module__`` set correctly.
|
||||
|
||||
2.13.0 (2010-02-14)
|
||||
-------------------
|
||||
|
||||
- Added support for method cache in Acquisition. Patch contributed by
|
||||
Yoshinori K. Okuji. See https://bugs.launchpad.net/zope2/+bug/486182.
|
||||
|
||||
2.12.4 (2009-10-29)
|
||||
-------------------
|
||||
|
||||
- Fix iteration proxying to pass `self` acquisition-wrapped into both
|
||||
`__iter__` as well as `__getitem__` (this fixes
|
||||
https://bugs.launchpad.net/zope2/+bug/360761).
|
||||
|
||||
- Add tests for the __getslice__ proxying, including open-ended slicing.
|
||||
|
||||
2.12.3 (2009-08-08)
|
||||
-------------------
|
||||
|
||||
- More 64-bit fixes in Py_BuildValue calls.
|
||||
|
||||
- More 64-bit issues fixed: Use correct integer size for slice operations.
|
||||
|
||||
2.12.2 (2009-08-02)
|
||||
-------------------
|
||||
|
||||
- Fixed 64-bit compatibility issues for Python 2.5.x / 2.6.x. See
|
||||
http://www.python.org/dev/peps/pep-0353/ for details.
|
||||
|
||||
2.12.1 (2009-04-15)
|
||||
-------------------
|
||||
|
||||
- Update for iteration proxying: The proxy for `__iter__` must not rely on the
|
||||
object to have an `__iter__` itself, but also support fall-back iteration via
|
||||
`__getitem__` (this fixes https://bugs.launchpad.net/zope2/+bug/360761).
|
||||
|
||||
2.12 (2009-01-25)
|
||||
-----------------
|
||||
|
||||
- Release as separate package.
|
||||
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 6 - Mature
|
||||
Classifier: Environment :: Web Environment
|
||||
Classifier: Framework :: Zope2
|
||||
Classifier: License :: OSI Approved :: Zope Public License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.4
|
||||
Classifier: Programming Language :: Python :: 3.5
|
||||
Classifier: Programming Language :: Python :: 3.6
|
||||
Classifier: Programming Language :: Python :: 3.7
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
@@ -0,0 +1,25 @@
|
||||
.coveragerc
|
||||
.gitignore
|
||||
CHANGES.rst
|
||||
COPYRIGHT.txt
|
||||
LICENSE.txt
|
||||
MANIFEST.in
|
||||
README.rst
|
||||
buildout.cfg
|
||||
pip-delete-this-directory.txt
|
||||
setup.cfg
|
||||
setup.py
|
||||
tox.ini
|
||||
include/ExtensionClass/ExtensionClass.h
|
||||
include/ExtensionClass/_compat.h
|
||||
src/Acquisition/Acquisition.h
|
||||
src/Acquisition/_Acquisition.c
|
||||
src/Acquisition/__init__.py
|
||||
src/Acquisition/interfaces.py
|
||||
src/Acquisition/tests.py
|
||||
src/Acquisition.egg-info/PKG-INFO
|
||||
src/Acquisition.egg-info/SOURCES.txt
|
||||
src/Acquisition.egg-info/dependency_links.txt
|
||||
src/Acquisition.egg-info/not-zip-safe
|
||||
src/Acquisition.egg-info/requires.txt
|
||||
src/Acquisition.egg-info/top_level.txt
|
||||
+1
@@ -0,0 +1 @@
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
../Acquisition/Acquisition.h
|
||||
../Acquisition/_Acquisition.c
|
||||
../Acquisition/_Acquisition.cpython-36m-darwin.so
|
||||
../Acquisition/__init__.py
|
||||
../Acquisition/__pycache__/__init__.cpython-36.pyc
|
||||
../Acquisition/__pycache__/interfaces.cpython-36.pyc
|
||||
../Acquisition/__pycache__/tests.cpython-36.pyc
|
||||
../Acquisition/interfaces.py
|
||||
../Acquisition/tests.py
|
||||
PKG-INFO
|
||||
SOURCES.txt
|
||||
dependency_links.txt
|
||||
not-zip-safe
|
||||
requires.txt
|
||||
top_level.txt
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ExtensionClass>=4.2.0
|
||||
zope.interface
|
||||
@@ -0,0 +1 @@
|
||||
Acquisition
|
||||
@@ -0,0 +1,53 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996-2002 Zope Foundation and Contributors.
|
||||
All Rights Reserved.
|
||||
|
||||
This software is subject to the provisions of the Zope Public License,
|
||||
Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ACQUISITION_H_
|
||||
#define __ACQUISITION_H_
|
||||
|
||||
typedef struct {
|
||||
PyObject *(*AQ_Acquire) (PyObject *obj, PyObject *name, PyObject *filter,
|
||||
PyObject *extra, int explicit, PyObject *deflt,
|
||||
int containment);
|
||||
PyObject *(*AQ_Get) (PyObject *obj, PyObject *name, PyObject *deflt,
|
||||
int containment);
|
||||
int (*AQ_IsWrapper) (PyObject *obj);
|
||||
PyObject *(*AQ_Base) (PyObject *obj);
|
||||
PyObject *(*AQ_Parent) (PyObject *obj);
|
||||
PyObject *(*AQ_Self) (PyObject *obj);
|
||||
PyObject *(*AQ_Inner) (PyObject *obj);
|
||||
PyObject *(*AQ_Chain) (PyObject *obj, int containment);
|
||||
} ACQUISITIONCAPI;
|
||||
|
||||
#ifndef _IN_ACQUISITION_C
|
||||
|
||||
#define aq_Acquire(obj, name, filter, extra, explicit, deflt, containment ) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Acquire(obj, name, filter, extra, explicit, deflt, containment)))
|
||||
#define aq_acquire(obj, name) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Acquire(obj, name, NULL, NULL, 1, NULL, 0)))
|
||||
#define aq_get(obj, name, deflt, containment) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Get(obj, name, deflt, containment)))
|
||||
#define aq_isWrapper(obj) (AcquisitionCAPI == NULL ? -1 : (AcquisitionCAPI->AQ_IsWrapper(obj)))
|
||||
#define aq_base(obj) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Base(obj)))
|
||||
#define aq_parent(obj) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Parent(obj)))
|
||||
#define aq_self(obj) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Self(obj)))
|
||||
#define aq_inner(obj) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Inner(obj)))
|
||||
#define aq_chain(obj, containment) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_CHain(obj, containment)))
|
||||
|
||||
static ACQUISITIONCAPI *AcquisitionCAPI = NULL;
|
||||
|
||||
#define aq_init() { \
|
||||
AcquisitionCAPI = PyCapsule_Import("Acquisition.AcquisitionCAPI", 0); \
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
BIN
Binary file not shown.
@@ -0,0 +1,953 @@
|
||||
from __future__ import absolute_import, print_function
|
||||
|
||||
# pylint:disable=W0212,R0911,R0912
|
||||
|
||||
|
||||
import os
|
||||
import operator
|
||||
import platform
|
||||
import sys
|
||||
import types
|
||||
import weakref
|
||||
|
||||
import ExtensionClass
|
||||
|
||||
from zope.interface import classImplements
|
||||
|
||||
from .interfaces import IAcquirer
|
||||
from .interfaces import IAcquisitionWrapper
|
||||
|
||||
IS_PYPY = getattr(platform, 'python_implementation', lambda: None)() == 'PyPy'
|
||||
IS_PURE = 'PURE_PYTHON' in os.environ
|
||||
|
||||
|
||||
class Acquired(object):
|
||||
"Marker for explicit acquisition"
|
||||
|
||||
|
||||
_NOT_FOUND = object() # marker
|
||||
|
||||
###
|
||||
# Helper functions
|
||||
###
|
||||
|
||||
|
||||
def _has__of__(obj):
|
||||
"""Check whether an object has an __of__ method for returning itself
|
||||
in the context of a container."""
|
||||
# It is necessary to check both the type (or we get into cycles)
|
||||
# as well as the presence of the method (or mixins of Base pre- or
|
||||
# post-class-creation as done in, e.g.,
|
||||
# zopefoundation/Persistence) can fail.
|
||||
return (isinstance(obj, ExtensionClass.Base) and
|
||||
hasattr(type(obj), '__of__'))
|
||||
|
||||
|
||||
def _apply_filter(predicate, inst, name, result, extra, orig):
|
||||
return predicate(orig, inst, name, result, extra)
|
||||
|
||||
|
||||
if sys.version_info < (3,):
|
||||
import copy_reg
|
||||
|
||||
def _rebound_method(method, wrapper):
|
||||
"""Returns a version of the method with self bound to `wrapper`"""
|
||||
if isinstance(method, types.MethodType):
|
||||
method = types.MethodType(method.im_func, wrapper, method.im_class)
|
||||
return method
|
||||
exec("""def _reraise(tp, value, tb=None):
|
||||
raise tp, value, tb
|
||||
""")
|
||||
else: # pragma: no cover (python 2 is currently our reference)
|
||||
import copyreg as copy_reg
|
||||
|
||||
def _rebound_method(method, wrapper):
|
||||
"""Returns a version of the method with self bound to `wrapper`"""
|
||||
if isinstance(method, types.MethodType):
|
||||
method = types.MethodType(method.__func__, wrapper)
|
||||
return method
|
||||
|
||||
def _reraise(tp, value, tb=None):
|
||||
if value is None:
|
||||
value = tp()
|
||||
if value.__traceback__ is not tb:
|
||||
raise value.with_traceback(tb)
|
||||
raise value
|
||||
|
||||
###
|
||||
# Wrapper object protocol, mostly ported from C directly
|
||||
###
|
||||
|
||||
|
||||
def _Wrapper_findspecial(wrapper, name):
|
||||
"""
|
||||
Looks up the special acquisition attributes of an object.
|
||||
:param str name: The attribute to find, with 'aq' already stripped.
|
||||
"""
|
||||
|
||||
result = _NOT_FOUND
|
||||
|
||||
if name == 'base':
|
||||
result = wrapper._obj
|
||||
while isinstance(result, _Wrapper) and result._obj is not None:
|
||||
result = result._obj
|
||||
elif name == 'parent':
|
||||
result = wrapper._container
|
||||
elif name == 'self':
|
||||
result = wrapper._obj
|
||||
elif name == 'explicit':
|
||||
if type(wrapper)._IS_IMPLICIT:
|
||||
result = ExplicitAcquisitionWrapper(
|
||||
wrapper._obj, wrapper._container)
|
||||
else:
|
||||
result = wrapper
|
||||
elif name == 'acquire':
|
||||
result = object.__getattribute__(wrapper, 'aq_acquire')
|
||||
elif name == 'chain':
|
||||
# XXX: C has a second implementation here
|
||||
result = aq_chain(wrapper)
|
||||
elif name == 'inContextOf':
|
||||
result = object.__getattribute__(wrapper, 'aq_inContextOf')
|
||||
elif name == 'inner':
|
||||
# XXX: C has a second implementation here
|
||||
result = aq_inner(wrapper)
|
||||
elif name == 'uncle':
|
||||
result = 'Bob'
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _Wrapper_acquire(wrapper, name,
|
||||
predicate=None, predicate_extra=None,
|
||||
orig_object=None,
|
||||
explicit=True, containment=True):
|
||||
"""
|
||||
Attempt to acquire the `name` from the parent of the wrapper.
|
||||
|
||||
:raises AttributeError: If the wrapper has no parent or the
|
||||
attribute cannot be found.
|
||||
"""
|
||||
|
||||
if wrapper._container is None:
|
||||
raise AttributeError(name)
|
||||
|
||||
search_self = True
|
||||
search_parent = True
|
||||
|
||||
# If the container has an acquisition wrapper itself, we'll use
|
||||
# _Wrapper_findattr to progress further
|
||||
if isinstance(wrapper._container, _Wrapper):
|
||||
if isinstance(wrapper._obj, _Wrapper):
|
||||
# try to optimize search by recognizing repeated objects in path
|
||||
if wrapper._obj._container is wrapper._container._container:
|
||||
search_parent = False
|
||||
elif wrapper._obj._container is wrapper._container._obj:
|
||||
search_self = False
|
||||
|
||||
# Don't search the container when the container of the container
|
||||
# is the same object as `wrapper`
|
||||
if wrapper._container._container is wrapper._obj:
|
||||
search_parent = False
|
||||
containment = True
|
||||
result = _Wrapper_findattr(wrapper._container, name,
|
||||
predicate=predicate,
|
||||
predicate_extra=predicate_extra,
|
||||
orig_object=orig_object,
|
||||
search_self=search_self,
|
||||
search_parent=search_parent,
|
||||
explicit=explicit,
|
||||
containment=containment)
|
||||
# XXX: Why does this branch of the C code check __of__,
|
||||
# but the next one doesn't?
|
||||
if _has__of__(result):
|
||||
result = result.__of__(wrapper)
|
||||
return result
|
||||
|
||||
# If the container has a __parent__ pointer, we create an
|
||||
# acquisition wrapper for it accordingly. Then we can proceed
|
||||
# with Wrapper_findattr, just as if the container had an
|
||||
# acquisition wrapper in the first place (see above).
|
||||
# NOTE: This mutates the wrapper
|
||||
elif hasattr(wrapper._container, '__parent__'):
|
||||
parent = wrapper._container.__parent__
|
||||
# Don't search the container when the parent of the parent
|
||||
# is the same object as 'self'
|
||||
if parent is wrapper._obj:
|
||||
search_parent = False
|
||||
elif isinstance(parent, _Wrapper) and parent._obj is wrapper._obj:
|
||||
# XXX: C code just does parent._obj, assumes its a wrapper
|
||||
search_parent = False
|
||||
|
||||
wrapper._container = ImplicitAcquisitionWrapper(
|
||||
wrapper._container, parent)
|
||||
return _Wrapper_findattr(wrapper._container, name,
|
||||
predicate=predicate,
|
||||
predicate_extra=predicate_extra,
|
||||
orig_object=orig_object,
|
||||
search_self=search_self,
|
||||
search_parent=search_parent,
|
||||
explicit=explicit,
|
||||
containment=containment)
|
||||
else:
|
||||
# The container is the end of the acquisition chain; if we
|
||||
# can't look up the attributes here, we can't look it up at all
|
||||
result = getattr(wrapper._container, name)
|
||||
if result is not Acquired:
|
||||
if predicate:
|
||||
if _apply_filter(predicate, wrapper._container, name,
|
||||
result, predicate_extra, orig_object):
|
||||
return (result.__of__(wrapper)
|
||||
if _has__of__(result) else result)
|
||||
else:
|
||||
raise AttributeError(name)
|
||||
else:
|
||||
if _has__of__(result):
|
||||
result = result.__of__(wrapper)
|
||||
return result
|
||||
|
||||
# this line cannot be reached
|
||||
raise AttributeError(name) # pragma: no cover
|
||||
|
||||
|
||||
def _Wrapper_findattr(wrapper, name,
|
||||
predicate=None, predicate_extra=None,
|
||||
orig_object=None,
|
||||
search_self=True, search_parent=True,
|
||||
explicit=True, containment=True):
|
||||
"""
|
||||
Search the `wrapper` object for the attribute `name`.
|
||||
|
||||
:param bool search_self: Search `wrapper.aq_self` for the attribute.
|
||||
:param bool search_parent: Search `wrapper.aq_parent` for the attribute.
|
||||
:param bool explicit: Explicitly acquire the attribute from the parent
|
||||
(should be assumed with implicit wrapper)
|
||||
:param bool containment: Use the innermost wrapper (`aq_inner`)
|
||||
for looking up the attribute.
|
||||
"""
|
||||
|
||||
orig_name = name
|
||||
if orig_object is None:
|
||||
orig_object = wrapper
|
||||
|
||||
# First, special names
|
||||
if name.startswith('aq') or name == '__parent__':
|
||||
# __parent__ is an alias of aq_parent
|
||||
if name == '__parent__':
|
||||
name = 'parent'
|
||||
else:
|
||||
name = name[3:]
|
||||
|
||||
result = _Wrapper_findspecial(wrapper, name)
|
||||
if result is not _NOT_FOUND:
|
||||
if predicate:
|
||||
if _apply_filter(predicate, wrapper, orig_name,
|
||||
result, predicate_extra, orig_object):
|
||||
return result
|
||||
else:
|
||||
raise AttributeError(orig_name)
|
||||
return result
|
||||
elif name in ('__reduce__', '__reduce_ex__', '__getstate__',
|
||||
'__of__', '__cmp__', '__eq__', '__ne__', '__lt__',
|
||||
'__le__', '__gt__', '__ge__'):
|
||||
return object.__getattribute__(wrapper, orig_name)
|
||||
|
||||
# If we're doing a containment search, replace the wrapper with aq_inner
|
||||
if containment:
|
||||
while isinstance(wrapper._obj, _Wrapper):
|
||||
wrapper = wrapper._obj
|
||||
|
||||
if search_self and wrapper._obj is not None:
|
||||
if isinstance(wrapper._obj, _Wrapper):
|
||||
if wrapper is wrapper._obj:
|
||||
raise RuntimeError("Recursion detected in acquisition wrapper")
|
||||
try:
|
||||
result = _Wrapper_findattr(wrapper._obj, orig_name,
|
||||
predicate=predicate,
|
||||
predicate_extra=predicate_extra,
|
||||
orig_object=orig_object,
|
||||
search_self=True,
|
||||
search_parent=explicit or isinstance(wrapper._obj, ImplicitAcquisitionWrapper), # NOQA
|
||||
explicit=explicit,
|
||||
containment=containment)
|
||||
if isinstance(result, types.MethodType):
|
||||
result = _rebound_method(result, wrapper)
|
||||
elif _has__of__(result):
|
||||
result = result.__of__(wrapper)
|
||||
return result
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
# deal with mixed __parent__ / aq_parent circles
|
||||
elif (isinstance(wrapper._container, _Wrapper) and
|
||||
wrapper._container._container is wrapper):
|
||||
raise RuntimeError("Recursion detected in acquisition wrapper")
|
||||
else:
|
||||
# normal attribute lookup
|
||||
try:
|
||||
result = getattr(wrapper._obj, orig_name)
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if result is Acquired:
|
||||
return _Wrapper_acquire(wrapper, orig_name,
|
||||
predicate=predicate,
|
||||
predicate_extra=predicate_extra,
|
||||
orig_object=orig_object,
|
||||
explicit=True,
|
||||
containment=containment)
|
||||
|
||||
if isinstance(result, types.MethodType):
|
||||
result = _rebound_method(result, wrapper)
|
||||
elif _has__of__(result):
|
||||
result = result.__of__(wrapper)
|
||||
|
||||
if predicate:
|
||||
if _apply_filter(predicate, wrapper, orig_name,
|
||||
result, predicate_extra, orig_object):
|
||||
return result
|
||||
else:
|
||||
return result
|
||||
|
||||
# lookup has failed, acquire from the parent
|
||||
if search_parent and (not name.startswith('_') or explicit):
|
||||
return _Wrapper_acquire(wrapper, orig_name,
|
||||
predicate=predicate,
|
||||
predicate_extra=predicate_extra,
|
||||
orig_object=orig_object,
|
||||
explicit=explicit,
|
||||
containment=containment)
|
||||
|
||||
raise AttributeError(orig_name)
|
||||
|
||||
|
||||
_NOT_GIVEN = object() # marker
|
||||
_OGA = object.__getattribute__
|
||||
|
||||
# Map from object types with slots to their generated, derived
|
||||
# types (or None if no derived type is needed)
|
||||
_wrapper_subclass_cache = weakref.WeakKeyDictionary()
|
||||
|
||||
|
||||
def _make_wrapper_subclass_if_needed(cls, obj, container):
|
||||
# If the type of an object to be wrapped has __slots__, then we
|
||||
# must create a wrapper subclass that has descriptors for those
|
||||
# same slots. In this way, its methods that use object.__getattribute__
|
||||
# directly will continue to work, even when given an instance of _Wrapper
|
||||
if getattr(cls, '_Wrapper__DERIVED', False):
|
||||
return None
|
||||
type_obj = type(obj)
|
||||
wrapper_subclass = _wrapper_subclass_cache.get(type_obj, _NOT_GIVEN)
|
||||
if wrapper_subclass is _NOT_GIVEN:
|
||||
slotnames = copy_reg._slotnames(type_obj)
|
||||
if slotnames and not isinstance(obj, _Wrapper):
|
||||
new_type_dict = {'_Wrapper__DERIVED': True}
|
||||
|
||||
def _make_property(slotname):
|
||||
return property(lambda s: getattr(s._obj, slotname),
|
||||
lambda s, v: setattr(s._obj, slotname, v),
|
||||
lambda s: delattr(s._obj, slotname))
|
||||
for slotname in slotnames:
|
||||
new_type_dict[slotname] = _make_property(slotname)
|
||||
new_type = type(cls.__name__ + '_' + type_obj.__name__,
|
||||
(cls,),
|
||||
new_type_dict)
|
||||
else:
|
||||
new_type = None
|
||||
wrapper_subclass = _wrapper_subclass_cache[type_obj] = new_type
|
||||
|
||||
return wrapper_subclass
|
||||
|
||||
|
||||
class _Wrapper(ExtensionClass.Base):
|
||||
__slots__ = ('_obj', '_container', '__dict__')
|
||||
_IS_IMPLICIT = None
|
||||
|
||||
def __new__(cls, obj, container):
|
||||
wrapper_subclass = _make_wrapper_subclass_if_needed(cls, obj, container) # NOQA
|
||||
if wrapper_subclass:
|
||||
inst = wrapper_subclass(obj, container)
|
||||
else:
|
||||
inst = super(_Wrapper, cls).__new__(cls)
|
||||
inst._obj = obj
|
||||
inst._container = container
|
||||
if hasattr(obj, '__dict__') and not isinstance(obj, _Wrapper):
|
||||
# Make our __dict__ refer to the same dict as the other object,
|
||||
# so that if it has methods that use `object.__getattribute__`
|
||||
# they still work. Note that because we have slots,
|
||||
# we won't interfere with the contents of that dict.
|
||||
object.__setattr__(inst, '__dict__', obj.__dict__)
|
||||
return inst
|
||||
|
||||
def __init__(self, obj, container):
|
||||
super(_Wrapper, self).__init__()
|
||||
self._obj = obj
|
||||
self._container = container
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name == '__parent__' or name == 'aq_parent':
|
||||
object.__setattr__(self, '_container', value)
|
||||
return
|
||||
if name == '_obj' or name == '_container':
|
||||
# should only happen at init time
|
||||
object.__setattr__(self, name, value)
|
||||
return
|
||||
|
||||
# If we are wrapping something, unwrap passed in wrappers
|
||||
if self._obj is None:
|
||||
raise AttributeError(
|
||||
'Attempt to set attribute on empty acquisition wrapper')
|
||||
|
||||
while value is not None and isinstance(value, _Wrapper):
|
||||
value = value._obj
|
||||
|
||||
setattr(self._obj, name, value)
|
||||
|
||||
def __delattr__(self, name):
|
||||
if name == '__parent__' or name == 'aq_parent':
|
||||
self._container = None
|
||||
else:
|
||||
delattr(self._obj, name)
|
||||
|
||||
def __getattribute__(self, name):
|
||||
if name in ('_obj', '_container'):
|
||||
return _OGA(self, name)
|
||||
if (_OGA(self, '_obj') is not None or
|
||||
_OGA(self, '_container') is not None):
|
||||
return _Wrapper_findattr(self, name, None, None, None, True,
|
||||
type(self)._IS_IMPLICIT, False, False)
|
||||
return _OGA(self, name)
|
||||
|
||||
def __of__(self, parent):
|
||||
# Based on __of__ in the C code;
|
||||
# simplify a layer of wrapping.
|
||||
|
||||
# We have to call the raw __of__ method or we recurse on our
|
||||
# own lookup (the C code does not have this issue, it can use
|
||||
# the wrapped __of__ method because it gets here via the
|
||||
# descriptor code path)...
|
||||
wrapper = self._obj.__of__(parent)
|
||||
if (not isinstance(wrapper, _Wrapper) or
|
||||
not isinstance(wrapper._container, _Wrapper)):
|
||||
return wrapper
|
||||
# but the returned wrapper should be based on this object's
|
||||
# wrapping chain
|
||||
wrapper._obj = self
|
||||
|
||||
while (isinstance(wrapper._obj, _Wrapper) and
|
||||
(wrapper._obj._container is wrapper._container._obj)):
|
||||
# Since we mutate the wrapper as we walk up, we must copy
|
||||
# XXX: This comes from the C implementation. Do we really need to
|
||||
# copy?
|
||||
wrapper = type(wrapper)(wrapper._obj, wrapper._container)
|
||||
wrapper._obj = wrapper._obj._obj
|
||||
return wrapper
|
||||
|
||||
def aq_acquire(self, name,
|
||||
filter=None, extra=None,
|
||||
explicit=True,
|
||||
default=_NOT_GIVEN,
|
||||
containment=False):
|
||||
try:
|
||||
return _Wrapper_findattr(self, name,
|
||||
predicate=filter,
|
||||
predicate_extra=extra,
|
||||
orig_object=self,
|
||||
search_self=True,
|
||||
search_parent=explicit or type(self)._IS_IMPLICIT, # NOQA
|
||||
explicit=explicit,
|
||||
containment=containment)
|
||||
except AttributeError:
|
||||
if default is _NOT_GIVEN:
|
||||
raise
|
||||
return default
|
||||
|
||||
acquire = aq_acquire
|
||||
|
||||
def aq_inContextOf(self, o, inner=True):
|
||||
return aq_inContextOf(self, o, inner=inner)
|
||||
|
||||
# Wrappers themselves are not picklable, but if the underlying
|
||||
# object has a _p_oid, then the __getnewargs__ method is allowed
|
||||
def __reduce__(self, *args):
|
||||
raise TypeError("Can't pickle objects in acquisition wrappers.")
|
||||
__reduce_ex__ = __reduce__
|
||||
__getstate__ = __reduce__
|
||||
|
||||
def __getnewargs__(self):
|
||||
return ()
|
||||
|
||||
# Equality and comparisons
|
||||
|
||||
def __hash__(self):
|
||||
# The C implementation doesn't pass the wrapper
|
||||
# to any __hash__ that the object implements,
|
||||
# so it can't access derived attributes.
|
||||
# (If that changes, just add this to __unary_special_methods__
|
||||
# and remove this method)
|
||||
return hash(self._obj)
|
||||
|
||||
# The C implementation forces all comparisons through the
|
||||
# __cmp__ method, if it's implemented. If it's not implemented,
|
||||
# then comparisons are based strictly on the memory addresses
|
||||
# of the underlying object (aq_base). We could mostly emulate
|
||||
# this behaviour on Python 2, but on Python 3 __cmp__ is gone,
|
||||
# so users won't have an expectation to write it.
|
||||
# Because users have never had an expectation that the rich comparison
|
||||
# methods would be called on their wrapped objects (and so would not be
|
||||
# accessing acquired attributes there), we can't/don't want to start
|
||||
# proxying to them?
|
||||
# For the moment, we settle for an emulation of the C behaviour:
|
||||
# define __cmp__ the same way, and redirect the rich comparison operators
|
||||
# to it. (Note that these attributes are also hardcoded in getattribute)
|
||||
def __cmp__(self, other):
|
||||
aq_self = self._obj
|
||||
if hasattr(type(aq_self), '__cmp__'):
|
||||
return _rebound_method(aq_self.__cmp__, self)(other)
|
||||
|
||||
my_base = aq_base(self)
|
||||
other_base = aq_base(other)
|
||||
if my_base is other_base:
|
||||
return 0
|
||||
return -1 if id(my_base) < id(other_base) else 1
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.__cmp__(other) == 0
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.__cmp__(other) != 0
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.__cmp__(other) < 0
|
||||
|
||||
def __le__(self, other):
|
||||
return self.__cmp__(other) <= 0
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.__cmp__(other) > 0
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.__cmp__(other) >= 0
|
||||
|
||||
# Special methods looked up by the type of self._obj,
|
||||
# but which must have the wrapper as self when called
|
||||
|
||||
def __nonzero__(self):
|
||||
aq_self = self._obj
|
||||
type_aq_self = type(aq_self)
|
||||
nonzero = getattr(type_aq_self, '__nonzero__', None)
|
||||
if nonzero is None:
|
||||
# Py3 bool?
|
||||
nonzero = getattr(type_aq_self, '__bool__', None)
|
||||
if nonzero is None:
|
||||
# a len?
|
||||
nonzero = getattr(type_aq_self, '__len__', None)
|
||||
if nonzero:
|
||||
return bool(nonzero(self)) # Py3 is strict about the return type
|
||||
# If nothing was defined, then it's true
|
||||
return True
|
||||
__bool__ = __nonzero__
|
||||
|
||||
def __unicode__(self):
|
||||
f = getattr(self.aq_self, '__unicode__',
|
||||
getattr(self.aq_self, '__str__', object.__str__))
|
||||
return _rebound_method(f, self)()
|
||||
|
||||
def __repr__(self):
|
||||
aq_self = self._obj
|
||||
try:
|
||||
return _rebound_method(aq_self.__repr__, self)()
|
||||
except (AttributeError, TypeError):
|
||||
return repr(aq_self)
|
||||
|
||||
def __str__(self):
|
||||
aq_self = self._obj
|
||||
try:
|
||||
return _rebound_method(aq_self.__str__, self)()
|
||||
except (AttributeError, TypeError): # pragma: no cover (Only Py3)
|
||||
return str(aq_self)
|
||||
|
||||
__binary_special_methods__ = [
|
||||
# general numeric
|
||||
'__add__',
|
||||
'__sub__',
|
||||
'__mul__',
|
||||
'__matmul__',
|
||||
'__floordiv__', # not implemented in C
|
||||
'__mod__',
|
||||
'__divmod__',
|
||||
'__pow__',
|
||||
'__lshift__',
|
||||
'__rshift__',
|
||||
'__and__',
|
||||
'__xor__',
|
||||
'__or__',
|
||||
|
||||
# division; only one of these will be used at any one time
|
||||
'__truediv__',
|
||||
'__div__',
|
||||
|
||||
# reflected numeric
|
||||
'__radd__',
|
||||
'__rsub__',
|
||||
'__rmul__',
|
||||
'__rdiv__',
|
||||
'__rtruediv__',
|
||||
'__rfloordiv__',
|
||||
'__rmod__',
|
||||
'__rdivmod__',
|
||||
'__rpow__',
|
||||
'__rlshift__',
|
||||
'__rrshift__',
|
||||
'__rand__',
|
||||
'__rxor__',
|
||||
'__ror__',
|
||||
|
||||
# in place numeric
|
||||
'__iadd__',
|
||||
'__isub__',
|
||||
'__imul__',
|
||||
'__imatmul__',
|
||||
'__idiv__',
|
||||
'__itruediv__',
|
||||
'__ifloordiv__',
|
||||
'__imod__',
|
||||
'__idivmod__',
|
||||
'__ipow__',
|
||||
'__ilshift__',
|
||||
'__irshift__',
|
||||
'__iand__',
|
||||
'__ixor__',
|
||||
'__ior__',
|
||||
|
||||
# conversion
|
||||
'__coerce__',
|
||||
|
||||
# container
|
||||
'__delitem__',
|
||||
]
|
||||
|
||||
__unary_special_methods__ = [
|
||||
# arithmetic
|
||||
'__neg__',
|
||||
'__pos__',
|
||||
'__abs__',
|
||||
'__invert__',
|
||||
|
||||
# conversion
|
||||
'__complex__',
|
||||
'__int__',
|
||||
'__long__',
|
||||
'__float__',
|
||||
'__oct__',
|
||||
'__hex__',
|
||||
'__index__',
|
||||
# '__len__',
|
||||
|
||||
# strings are special
|
||||
# '__repr__',
|
||||
# '__str__',
|
||||
]
|
||||
|
||||
for _name in __binary_special_methods__:
|
||||
def _make_op(_name):
|
||||
def op(self, other):
|
||||
aq_self = self._obj
|
||||
return getattr(type(aq_self), _name)(self, other)
|
||||
return op
|
||||
locals()[_name] = _make_op(_name)
|
||||
|
||||
for _name in __unary_special_methods__:
|
||||
def _make_op(_name):
|
||||
def op(self):
|
||||
aq_self = self._obj
|
||||
return getattr(type(aq_self), _name)(self)
|
||||
return op
|
||||
locals()[_name] = _make_op(_name)
|
||||
|
||||
del _make_op
|
||||
del _name
|
||||
|
||||
# Container protocol
|
||||
|
||||
def __len__(self):
|
||||
# if len is missing, it should raise TypeError
|
||||
# (AttributeError is acceptable under Py2, but Py3
|
||||
# breaks list conversion if AttributeError is raised)
|
||||
try:
|
||||
l = getattr(type(self._obj), '__len__')
|
||||
except AttributeError:
|
||||
raise TypeError('object has no len()')
|
||||
else:
|
||||
return l(self)
|
||||
|
||||
def __iter__(self):
|
||||
# For things that provide either __iter__ or just __getitem__,
|
||||
# we need to be sure that the wrapper is provided as self
|
||||
if hasattr(self._obj, '__iter__'):
|
||||
return _rebound_method(self._obj.__iter__, self)()
|
||||
if hasattr(self._obj, '__getitem__'):
|
||||
# Unfortunately we cannot simply call iter(self._obj)
|
||||
# and rebind im_self like we do above: the Python runtime
|
||||
# complains:
|
||||
# (TypeError: 'sequenceiterator' expected, got 'Wrapper' instead)
|
||||
|
||||
class WrapperIter(object):
|
||||
__slots__ = ('_wrapper',)
|
||||
|
||||
def __init__(self, o):
|
||||
self._wrapper = o
|
||||
|
||||
def __getitem__(self, i):
|
||||
return self._wrapper.__getitem__(i)
|
||||
it = WrapperIter(self)
|
||||
return iter(it)
|
||||
|
||||
return iter(self._obj)
|
||||
|
||||
def __contains__(self, item):
|
||||
# First, if the type of the object defines __contains__ then
|
||||
# use it
|
||||
aq_self = self._obj
|
||||
aq_contains = getattr(type(aq_self), '__contains__', None)
|
||||
if aq_contains:
|
||||
return aq_contains(self, item)
|
||||
# Next, we should attempt to iterate like the interpreter;
|
||||
# but the C code doesn't do this, so we don't either.
|
||||
# return item in iter(self)
|
||||
raise AttributeError('__contains__')
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
aq_self = self._obj
|
||||
try:
|
||||
setter = type(aq_self).__setitem__
|
||||
except AttributeError:
|
||||
raise AttributeError("__setitem__") # doctests care about the name
|
||||
else:
|
||||
setter(self, key, value)
|
||||
|
||||
def __getitem__(self, key):
|
||||
if isinstance(key, slice) and hasattr(operator, 'getslice'):
|
||||
# Only on Python 2
|
||||
# XXX: This is probably not proxying correctly, but the existing
|
||||
# tests pass with this behaviour
|
||||
return operator.getslice(
|
||||
self._obj,
|
||||
key.start if key.start is not None else 0,
|
||||
key.stop if key.stop is not None else sys.maxint)
|
||||
|
||||
aq_self = self._obj
|
||||
try:
|
||||
getter = type(aq_self).__getitem__
|
||||
except AttributeError:
|
||||
raise AttributeError("__getitem__") # doctests care about the name
|
||||
else:
|
||||
return getter(self, key)
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
try:
|
||||
# Note we look this up on the completely unwrapped
|
||||
# object, so as not to get a class
|
||||
call = getattr(self.aq_base, '__call__')
|
||||
except AttributeError: # pragma: no cover
|
||||
# A TypeError is what the interpreter raises;
|
||||
# AttributeError is allowed to percolate through the
|
||||
# C proxy
|
||||
raise TypeError('object is not callable')
|
||||
else:
|
||||
return _rebound_method(call, self)(*args, **kwargs)
|
||||
|
||||
|
||||
class ImplicitAcquisitionWrapper(_Wrapper):
|
||||
_IS_IMPLICIT = True
|
||||
|
||||
|
||||
class ExplicitAcquisitionWrapper(_Wrapper):
|
||||
_IS_IMPLICIT = False
|
||||
|
||||
def __getattribute__(self, name):
|
||||
# Special case backwards-compatible acquire method
|
||||
if name == 'acquire':
|
||||
return object.__getattribute__(self, name)
|
||||
|
||||
return _Wrapper.__getattribute__(self, name)
|
||||
|
||||
|
||||
class _Acquirer(ExtensionClass.Base):
|
||||
|
||||
def __getattribute__(self, name):
|
||||
try:
|
||||
return super(_Acquirer, self).__getattribute__(name)
|
||||
except AttributeError:
|
||||
# the doctests have very specific error message
|
||||
# requirements (but at least we can preserve the traceback)
|
||||
_, _, tb = sys.exc_info()
|
||||
try:
|
||||
_reraise(AttributeError, AttributeError(name), tb)
|
||||
finally:
|
||||
del tb
|
||||
|
||||
def __of__(self, context):
|
||||
return type(self)._Wrapper(self, context)
|
||||
|
||||
|
||||
class Implicit(_Acquirer):
|
||||
_Wrapper = ImplicitAcquisitionWrapper
|
||||
|
||||
|
||||
ImplicitAcquisitionWrapper._Wrapper = ImplicitAcquisitionWrapper
|
||||
|
||||
|
||||
class Explicit(_Acquirer):
|
||||
_Wrapper = ExplicitAcquisitionWrapper
|
||||
|
||||
|
||||
ExplicitAcquisitionWrapper._Wrapper = ExplicitAcquisitionWrapper
|
||||
|
||||
###
|
||||
# Exported module functions
|
||||
###
|
||||
|
||||
|
||||
def aq_acquire(obj, name,
|
||||
filter=None, extra=None,
|
||||
explicit=True,
|
||||
default=_NOT_GIVEN,
|
||||
containment=False):
|
||||
if isinstance(obj, _Wrapper):
|
||||
return obj.aq_acquire(name,
|
||||
filter=filter, extra=extra,
|
||||
default=default,
|
||||
explicit=explicit or type(obj)._IS_IMPLICIT,
|
||||
containment=containment)
|
||||
|
||||
# Does it have a parent, or do we have a filter?
|
||||
# Then go through the acquisition code
|
||||
if hasattr(obj, '__parent__') or filter is not None:
|
||||
parent = getattr(obj, '__parent__', None)
|
||||
return aq_acquire(ImplicitAcquisitionWrapper(obj, parent),
|
||||
name,
|
||||
filter=filter, extra=extra,
|
||||
default=default,
|
||||
explicit=explicit,
|
||||
containment=containment)
|
||||
|
||||
# no parent and no filter, simple case
|
||||
try:
|
||||
return getattr(obj, name)
|
||||
except AttributeError:
|
||||
if default is _NOT_GIVEN:
|
||||
raise AttributeError(name) # doctests are strict
|
||||
return default
|
||||
|
||||
|
||||
def aq_parent(obj):
|
||||
# needs to be safe to call from __getattribute__ of a wrapper
|
||||
# and reasonably fast
|
||||
if isinstance(obj, _Wrapper):
|
||||
return object.__getattribute__(obj, '_container')
|
||||
# if not a wrapper, deal with the __parent__
|
||||
return getattr(obj, '__parent__', None)
|
||||
|
||||
|
||||
def aq_chain(obj, containment=False):
|
||||
result = []
|
||||
|
||||
while True:
|
||||
if isinstance(obj, _Wrapper):
|
||||
if obj._obj is not None:
|
||||
if containment:
|
||||
while isinstance(obj._obj, _Wrapper):
|
||||
obj = obj._obj
|
||||
result.append(obj)
|
||||
if obj._container is not None:
|
||||
obj = obj._container
|
||||
continue
|
||||
else:
|
||||
result.append(obj)
|
||||
obj = getattr(obj, '__parent__', None)
|
||||
if obj is not None:
|
||||
continue
|
||||
|
||||
break
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def aq_base(obj):
|
||||
result = obj
|
||||
while isinstance(result, _Wrapper):
|
||||
result = result._obj
|
||||
return result
|
||||
|
||||
|
||||
def aq_get(obj, name, default=_NOT_GIVEN, containment=False):
|
||||
|
||||
# Not wrapped. If we have a __parent__ pointer, create a wrapper
|
||||
# and go as usual
|
||||
if not isinstance(obj, _Wrapper) and hasattr(obj, '__parent__'):
|
||||
obj = ImplicitAcquisitionWrapper(obj, obj.__parent__)
|
||||
|
||||
try:
|
||||
# We got a wrapped object, business as usual
|
||||
return (_Wrapper_findattr(obj, name, None, None, obj,
|
||||
True, True, True, containment)
|
||||
if isinstance(obj, _Wrapper)
|
||||
# ok, plain getattr
|
||||
else getattr(obj, name))
|
||||
except AttributeError:
|
||||
if default is _NOT_GIVEN:
|
||||
raise
|
||||
return default
|
||||
|
||||
|
||||
def aq_inner(obj):
|
||||
if not isinstance(obj, _Wrapper):
|
||||
return obj
|
||||
|
||||
result = obj._obj
|
||||
while isinstance(result, _Wrapper):
|
||||
obj = result
|
||||
result = result._obj
|
||||
result = obj
|
||||
return result
|
||||
|
||||
|
||||
def aq_self(obj):
|
||||
if isinstance(obj, _Wrapper):
|
||||
return obj.aq_self
|
||||
return obj
|
||||
|
||||
|
||||
def aq_inContextOf(self, o, inner=True):
|
||||
next = self
|
||||
o = aq_base(o)
|
||||
|
||||
while True:
|
||||
if aq_base(next) is o:
|
||||
return True
|
||||
|
||||
if inner:
|
||||
self = aq_inner(next)
|
||||
if self is None: # pragma: no cover
|
||||
# This branch is normally impossible to hit,
|
||||
# it just mirrors a check in C
|
||||
break
|
||||
else:
|
||||
self = next
|
||||
|
||||
next = aq_parent(self)
|
||||
if next is None:
|
||||
break
|
||||
|
||||
return False
|
||||
|
||||
|
||||
if not (IS_PYPY or IS_PURE): # pragma: no cover
|
||||
# Make sure we can import the C extension of our dependency.
|
||||
from ExtensionClass import _ExtensionClass # NOQA
|
||||
from ._Acquisition import * # NOQA
|
||||
|
||||
classImplements(Explicit, IAcquirer)
|
||||
classImplements(ExplicitAcquisitionWrapper, IAcquisitionWrapper)
|
||||
classImplements(Implicit, IAcquirer)
|
||||
classImplements(ImplicitAcquisitionWrapper, IAcquisitionWrapper)
|
||||
@@ -0,0 +1,62 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2005 Zope Foundation and Contributors.
|
||||
#
|
||||
# This software is subject to the provisions of the Zope Public License,
|
||||
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
##############################################################################
|
||||
"""Acquisition z3 interfaces.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope.interface import Attribute
|
||||
from zope.interface import Interface
|
||||
|
||||
|
||||
class IAcquirer(Interface):
|
||||
|
||||
"""Acquire attributes from containers.
|
||||
"""
|
||||
|
||||
def __of__(context):
|
||||
"""Get the object in a context.
|
||||
"""
|
||||
|
||||
|
||||
class IAcquisitionWrapper(Interface):
|
||||
|
||||
"""Wrapper object for acquisition.
|
||||
"""
|
||||
|
||||
def aq_acquire(name, filter=None, extra=None, explicit=True, default=0,
|
||||
containment=0):
|
||||
"""Get an attribute, acquiring it if necessary.
|
||||
"""
|
||||
|
||||
def aq_inContextOf(obj, inner=1):
|
||||
"""Test whether the object is currently in the context of the argument.
|
||||
"""
|
||||
|
||||
aq_base = Attribute(
|
||||
"""Get the object unwrapped.""")
|
||||
|
||||
aq_parent = Attribute(
|
||||
"""Get the parent of an object.""")
|
||||
|
||||
aq_self = Attribute(
|
||||
"""Get the object with the outermost wrapper removed.""")
|
||||
|
||||
aq_inner = Attribute(
|
||||
"""Get the object with all but the innermost wrapper removed.""")
|
||||
|
||||
aq_chain = Attribute(
|
||||
"""Get a list of objects in the acquisition environment.""")
|
||||
|
||||
aq_explicit = Attribute(
|
||||
"""Get the object with an explicit acquisition wrapper.""")
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,25 @@
|
||||
Overview
|
||||
========
|
||||
|
||||
AuthEncoding is a framework for handling LDAP style password hashes.
|
||||
|
||||
It is used in Zope2 but does not depend on any other Zope package.
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
4.0.0 (2015-09-30)
|
||||
------------------
|
||||
|
||||
- Supporting Python 3.3 up to 3.5 and PyPy2.
|
||||
|
||||
- Added ``SHA256DigestScheme``.
|
||||
|
||||
|
||||
3.0.0 (2015-09-28)
|
||||
------------------
|
||||
|
||||
- Extracted from ``AccessControl 3.0.11``
|
||||
|
||||
|
||||
|
||||
File renamed without changes.
@@ -0,0 +1,54 @@
|
||||
Metadata-Version: 2.0
|
||||
Name: AuthEncoding
|
||||
Version: 4.0.0
|
||||
Summary: Framework for handling LDAP style password hashes.
|
||||
Home-page: https://github.com/zopefoundation/AuthEncoding
|
||||
Author: Zope Foundation and Contributors
|
||||
Author-email: zope-dev@zope.org
|
||||
License: ZPL 2.1
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 6 - Mature
|
||||
Classifier: Environment :: Web Environment
|
||||
Classifier: Framework :: Zope2
|
||||
Classifier: License :: OSI Approved :: Zope Public License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.3
|
||||
Classifier: Programming Language :: Python :: 3.4
|
||||
Classifier: Programming Language :: Python :: 3.5
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Classifier: Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP
|
||||
Requires-Dist: six
|
||||
Provides-Extra: test
|
||||
Requires-Dist: pytest; extra == 'test'
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
AuthEncoding is a framework for handling LDAP style password hashes.
|
||||
|
||||
It is used in Zope2 but does not depend on any other Zope package.
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
4.0.0 (2015-09-30)
|
||||
------------------
|
||||
|
||||
- Supporting Python 3.3 up to 3.5 and PyPy2.
|
||||
|
||||
- Added ``SHA256DigestScheme``.
|
||||
|
||||
|
||||
3.0.0 (2015-09-28)
|
||||
------------------
|
||||
|
||||
- Extracted from ``AccessControl 3.0.11``
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
AuthEncoding-4.0.0.dist-info/DESCRIPTION.rst,sha256=UKoEVLqA6eoGuaGlkVcj4mZJUnzBr3IdyZ4rLj9tBY4,381
|
||||
AuthEncoding-4.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
AuthEncoding-4.0.0.dist-info/METADATA,sha256=LMz4ZjZ94m7OrJJAs4_0fs1X4C-gvWPTEw8uGwX-LvY,1588
|
||||
AuthEncoding-4.0.0.dist-info/RECORD,,
|
||||
AuthEncoding-4.0.0.dist-info/RECORD.jws,,
|
||||
AuthEncoding-4.0.0.dist-info/WHEEL,sha256=5wvfB7GvgZAbKBSE9uX9Zbi6LCL-_KgezgHblXhCRnM,113
|
||||
AuthEncoding-4.0.0.dist-info/metadata.json,sha256=yBATAjh7I5YnUKtIQHGhhActRCg60BSsaAeM0r5dPFY,1294
|
||||
AuthEncoding-4.0.0.dist-info/top_level.txt,sha256=r_cFzzt28gdOYPoRX7HjrbsJE6G-ZPK0n3sWbqE4PdQ,13
|
||||
AuthEncoding/AuthEncoding.py,sha256=A82pAZQA-r1NSG7jBf1qDJn4utAQXMHMSF09Do35t0w,7265
|
||||
AuthEncoding/__init__.py,sha256=9fdxLPEIHDUW2ig-pE92y7BkZAHItLvvFpgXTs4byiU,791
|
||||
AuthEncoding/__pycache__/AuthEncoding.cpython-36.pyc,,
|
||||
AuthEncoding/__pycache__/__init__.cpython-36.pyc,,
|
||||
AuthEncoding/__pycache__/compat.cpython-36.pyc,,
|
||||
AuthEncoding/compat.py,sha256=o2nbexNN16x67B8xLKZRQQo_F4LheBnRtKgO---vuPY,347
|
||||
AuthEncoding/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
AuthEncoding/tests/__pycache__/__init__.cpython-36.pyc,,
|
||||
AuthEncoding/tests/__pycache__/test_AuthEncoding.cpython-36.pyc,,
|
||||
AuthEncoding/tests/test_AuthEncoding.py,sha256=zEj6Uz2eC3VPxmafNcy2ZvdSQLfVSu_Yf9X63X2XHfM,3814
|
||||
@@ -0,0 +1 @@
|
||||
{"payload": "eyJoYXNoIjogInNoYTI1Nj1FbUpVbjFTUEdYeXhKc2FnMWpxNGJkMnlnYW80TlhzY2hORW5iSEFISHdnIn0", "recipients": [{"header": "eyJhbGciOiAiRWQyNTUxOSIsICJqd2siOiB7Imt0eSI6ICJFZDI1NTE5IiwgInZrIjogInZUZU1lalVPMTV1SkQzY203enZPLV9oc0dMSld4ZlFNMEFFd2R5SUQyeTQifX0", "signature": "D1i5q57sD-x3nU_8L_49SwW7b--DjetQhUpnMDwDDui6PVsLfsAr65teCK_GbT4txrxkqzCHEMV8byYKzz4XDw"}]}
|
||||
@@ -0,0 +1,6 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.30.0.a0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py2-none-any
|
||||
Tag: py3-none-any
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"classifiers": ["Development Status :: 6 - Mature", "Environment :: Web Environment", "Framework :: Zope2", "License :: OSI Approved :: Zope Public License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP"], "extensions": {"python.details": {"contacts": [{"email": "zope-dev@zope.org", "name": "Zope Foundation and Contributors", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/zopefoundation/AuthEncoding"}}}, "extras": ["test"], "generator": "bdist_wheel (0.30.0.a0)", "license": "ZPL 2.1", "metadata_version": "2.0", "name": "AuthEncoding", "run_requires": [{"extra": "test", "requires": ["pytest"]}, {"requires": ["six"]}], "summary": "Framework for handling LDAP style password hashes.", "version": "4.0.0"}
|
||||
@@ -0,0 +1 @@
|
||||
AuthEncoding
|
||||
@@ -0,0 +1,253 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2002, 2015 Zope Foundation and Contributors.
|
||||
#
|
||||
# This software is subject to the provisions of the Zope Public License,
|
||||
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import binascii
|
||||
import six
|
||||
from binascii import b2a_base64, a2b_base64
|
||||
from hashlib import sha1 as sha
|
||||
from hashlib import sha256
|
||||
from os import getpid
|
||||
import time
|
||||
from .compat import long, b, u
|
||||
|
||||
|
||||
# Use the system PRNG if possible
|
||||
import random
|
||||
try:
|
||||
random = random.SystemRandom()
|
||||
using_sysrandom = True
|
||||
except NotImplementedError:
|
||||
using_sysrandom = False
|
||||
|
||||
|
||||
def _reseed():
|
||||
if not using_sysrandom:
|
||||
# This is ugly, and a hack, but it makes things better than
|
||||
# the alternative of predictability. This re-seeds the PRNG
|
||||
# using a value that is hard for an attacker to predict, every
|
||||
# time a random string is required. This may change the
|
||||
# properties of the chosen random sequence slightly, but this
|
||||
# is better than absolute predictability.
|
||||
random.seed(sha256(
|
||||
"%s%s%s" % (random.getstate(), time.time(), getpid())
|
||||
).digest())
|
||||
|
||||
|
||||
def _choice(c):
|
||||
_reseed()
|
||||
return random.choice(c)
|
||||
|
||||
|
||||
def _randrange(r):
|
||||
_reseed()
|
||||
return random.randrange(r)
|
||||
|
||||
|
||||
def constant_time_compare(val1, val2):
|
||||
"""
|
||||
Returns True if the two strings are equal, False otherwise.
|
||||
|
||||
The time taken is independent of the number of characters that match.
|
||||
"""
|
||||
if len(val1) != len(val2):
|
||||
return False
|
||||
result = 0
|
||||
for x, y in zip(six.iterbytes(val1), six.iterbytes(val2)):
|
||||
result |= x ^ y
|
||||
return result == 0
|
||||
|
||||
|
||||
class PasswordEncryptionScheme: # An Interface
|
||||
|
||||
def encrypt(pw):
|
||||
"""
|
||||
Encrypt the provided plain text password.
|
||||
"""
|
||||
|
||||
def validate(reference, attempt):
|
||||
"""
|
||||
Validate the provided password string. Reference is the
|
||||
correct password, which may be encrypted; attempt is clear text
|
||||
password attempt.
|
||||
"""
|
||||
|
||||
|
||||
_schemes = []
|
||||
|
||||
|
||||
def registerScheme(id, s):
|
||||
'''
|
||||
Registers an LDAP password encoding scheme.
|
||||
'''
|
||||
_schemes.append((id, u'{%s}' % id, s))
|
||||
|
||||
|
||||
def listSchemes():
|
||||
return [id for id, prefix, scheme in _schemes]
|
||||
|
||||
|
||||
class SSHADigestScheme:
|
||||
'''
|
||||
SSHA is a modification of the SHA digest scheme with a salt
|
||||
starting at byte 20 of the base64-encoded string.
|
||||
'''
|
||||
# Source: http://developer.netscape.com/docs/technote/ldap/pass_sha.html
|
||||
|
||||
def generate_salt(self):
|
||||
# Salt can be any length, but not more than about 37 characters
|
||||
# because of limitations of the binascii module.
|
||||
# 7 is what Netscape's example used and should be enough.
|
||||
# All 256 characters are available.
|
||||
salt = b''
|
||||
for n in range(7):
|
||||
salt += six.int2byte(_randrange(256))
|
||||
return salt
|
||||
|
||||
def encrypt(self, pw):
|
||||
return self._encrypt_with_salt(pw, self.generate_salt())
|
||||
|
||||
def validate(self, reference, attempt):
|
||||
try:
|
||||
ref = a2b_base64(reference)
|
||||
except binascii.Error:
|
||||
# Not valid base64.
|
||||
return 0
|
||||
salt = ref[20:]
|
||||
compare = self._encrypt_with_salt(attempt, salt)
|
||||
return constant_time_compare(compare, reference)
|
||||
|
||||
def _encrypt_with_salt(self, pw, salt):
|
||||
pw = b(pw)
|
||||
return b2a_base64(sha(pw + salt).digest() + salt)[:-1]
|
||||
|
||||
registerScheme(u'SSHA', SSHADigestScheme())
|
||||
|
||||
|
||||
class SHADigestScheme:
|
||||
|
||||
def encrypt(self, pw):
|
||||
return self._encrypt(pw)
|
||||
|
||||
def validate(self, reference, attempt):
|
||||
compare = self._encrypt(attempt)
|
||||
return constant_time_compare(compare, reference)
|
||||
|
||||
def _encrypt(self, pw):
|
||||
pw = b(pw)
|
||||
return b2a_base64(sha(pw).digest())[:-1]
|
||||
|
||||
|
||||
registerScheme(u'SHA', SHADigestScheme())
|
||||
|
||||
|
||||
class SHA256DigestScheme:
|
||||
|
||||
def encrypt(self, pw):
|
||||
return b(sha256(b(pw)).hexdigest())
|
||||
|
||||
def validate(self, reference, attempt):
|
||||
a = self.encrypt(attempt)
|
||||
return constant_time_compare(a, reference)
|
||||
|
||||
registerScheme(u'SHA256', SHA256DigestScheme())
|
||||
|
||||
|
||||
# Bogosity on various platforms due to ITAR restrictions
|
||||
try:
|
||||
from crypt import crypt
|
||||
except ImportError:
|
||||
crypt = None
|
||||
|
||||
if crypt is not None:
|
||||
|
||||
class CryptDigestScheme:
|
||||
|
||||
def generate_salt(self):
|
||||
choices = (u"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
u"abcdefghijklmnopqrstuvwxyz"
|
||||
u"0123456789./")
|
||||
return _choice(choices) + _choice(choices)
|
||||
|
||||
def encrypt(self, pw):
|
||||
return b(crypt(self._recode_password(pw), self.generate_salt()))
|
||||
|
||||
def validate(self, reference, attempt):
|
||||
attempt = self._recode_password(attempt)
|
||||
a = b(crypt(attempt, reference[:2].decode('ascii')))
|
||||
return constant_time_compare(a, reference)
|
||||
|
||||
def _recode_password(self, pw):
|
||||
# crypt always requires `str` which has a different meaning among
|
||||
# the Python versions:
|
||||
if six.PY3:
|
||||
return u(pw)
|
||||
return b(pw)
|
||||
|
||||
registerScheme(u'CRYPT', CryptDigestScheme())
|
||||
|
||||
|
||||
class MySQLDigestScheme:
|
||||
|
||||
def encrypt(self, pw):
|
||||
pw = u(pw)
|
||||
nr = long(1345345333)
|
||||
add = 7
|
||||
nr2 = long(0x12345671)
|
||||
for i in pw:
|
||||
if i == ' ' or i == '\t':
|
||||
continue
|
||||
nr ^= (((nr & 63) + add) * ord(i)) + (nr << 8)
|
||||
nr2 += (nr2 << 8) ^ nr
|
||||
add += ord(i)
|
||||
r0 = nr & ((long(1) << 31) - long(1))
|
||||
r1 = nr2 & ((long(1) << 31) - long(1))
|
||||
return (u"%08lx%08lx" % (r0, r1)).encode('ascii')
|
||||
|
||||
def validate(self, reference, attempt):
|
||||
a = self.encrypt(attempt)
|
||||
return constant_time_compare(a, reference)
|
||||
|
||||
registerScheme(u'MYSQL', MySQLDigestScheme())
|
||||
|
||||
|
||||
def pw_validate(reference, attempt):
|
||||
"""Validate the provided password string, which uses LDAP-style encoding
|
||||
notation. Reference is the correct password, attempt is clear text
|
||||
password attempt."""
|
||||
reference = b(reference)
|
||||
for id, prefix, scheme in _schemes:
|
||||
lp = len(prefix)
|
||||
if reference[:lp] == b(prefix):
|
||||
return scheme.validate(reference[lp:], attempt)
|
||||
# Assume cleartext.
|
||||
return constant_time_compare(reference, b(attempt))
|
||||
|
||||
|
||||
def is_encrypted(pw):
|
||||
for id, prefix, scheme in _schemes:
|
||||
lp = len(prefix)
|
||||
if pw[:lp] == b(prefix):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def pw_encrypt(pw, encoding=u'SSHA'):
|
||||
"""Encrypt the provided plain text password using the encoding if provided
|
||||
and return it in an LDAP-style representation."""
|
||||
encoding = u(encoding)
|
||||
for id, prefix, scheme in _schemes:
|
||||
if encoding == id:
|
||||
return b(prefix) + scheme.encrypt(pw)
|
||||
raise ValueError('Not supported: %s' % encoding)
|
||||
|
||||
pw_encode = pw_encrypt # backward compatibility
|
||||
@@ -0,0 +1,17 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2002,2015 Zope Foundation and Contributors.
|
||||
#
|
||||
# This software is subject to the provisions of the Zope Public License,
|
||||
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
from .AuthEncoding import (is_encrypted, pw_encrypt, pw_validate,
|
||||
registerScheme, listSchemes,
|
||||
constant_time_compare)
|
||||
@@ -0,0 +1,20 @@
|
||||
import six
|
||||
|
||||
if six.PY3:
|
||||
long = int
|
||||
else:
|
||||
long = long
|
||||
|
||||
|
||||
def b(arg):
|
||||
"""Convert `arg` to bytes."""
|
||||
if isinstance(arg, six.text_type):
|
||||
arg = arg.encode("latin-1")
|
||||
return arg
|
||||
|
||||
|
||||
def u(arg):
|
||||
"""Convert `arg` to text."""
|
||||
if isinstance(arg, six.binary_type):
|
||||
arg = arg.decode('ascii', 'replace')
|
||||
return arg
|
||||
Whitespace-only changes.
@@ -0,0 +1,101 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2002, 2015 Zope Foundation and Contributors.
|
||||
#
|
||||
# This software is subject to the provisions of the Zope Public License,
|
||||
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE
|
||||
#
|
||||
##############################################################################
|
||||
"""Test of AuthEncoding
|
||||
"""
|
||||
|
||||
from AuthEncoding import AuthEncoding
|
||||
from ..compat import b, u
|
||||
import pytest
|
||||
|
||||
|
||||
def testListSchemes():
|
||||
assert len(AuthEncoding.listSchemes()) > 0 # At least one must exist!
|
||||
|
||||
|
||||
@pytest.mark.parametrize('schema_id', AuthEncoding.listSchemes())
|
||||
@pytest.mark.parametrize('password', [u'good_pw', u'gööd_pw', b(u'gööd_pw')])
|
||||
def testGoodPassword(schema_id, password):
|
||||
enc = AuthEncoding.pw_encrypt(password, schema_id)
|
||||
assert enc != password
|
||||
assert AuthEncoding.pw_validate(enc, password)
|
||||
assert AuthEncoding.pw_validate(u(enc), password)
|
||||
assert AuthEncoding.is_encrypted(enc)
|
||||
assert not AuthEncoding.is_encrypted(password)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('schema_id', AuthEncoding.listSchemes())
|
||||
@pytest.mark.parametrize(
|
||||
'password', [u'OK_pa55w0rd \n', u'OK_pä55w0rd \n', b(u'OK_pä55w0rd \n')])
|
||||
def testBadPassword(schema_id, password):
|
||||
enc = AuthEncoding.pw_encrypt(password, schema_id)
|
||||
assert enc != password
|
||||
assert not AuthEncoding.pw_validate(enc, u'xxx')
|
||||
assert not AuthEncoding.pw_validate(enc, b'xxx')
|
||||
assert not AuthEncoding.pw_validate(u(enc), u'xxx')
|
||||
assert not AuthEncoding.pw_validate(enc, enc)
|
||||
if schema_id != u'CRYPT':
|
||||
# crypt truncates passwords and would fail this test.
|
||||
assert not AuthEncoding.pw_validate(enc, password[:-1])
|
||||
assert not AuthEncoding.pw_validate(enc, password[1:])
|
||||
assert AuthEncoding.pw_validate(enc, password)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('schema_id', AuthEncoding.listSchemes())
|
||||
def testShortPassword(schema_id):
|
||||
pw = u'1'
|
||||
enc = AuthEncoding.pw_encrypt(pw, schema_id)
|
||||
assert AuthEncoding.pw_validate(enc, pw)
|
||||
assert not AuthEncoding.pw_validate(enc, enc)
|
||||
assert not AuthEncoding.pw_validate(enc, u'xxx')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('schema_id', AuthEncoding.listSchemes())
|
||||
def testLongPassword(schema_id):
|
||||
pw = u'Pw' * 2000
|
||||
enc = AuthEncoding.pw_encrypt(pw, schema_id)
|
||||
assert AuthEncoding.pw_validate(enc, pw)
|
||||
assert not AuthEncoding.pw_validate(enc, enc)
|
||||
assert not AuthEncoding.pw_validate(enc, u'xxx')
|
||||
if u'CRYPT' not in schema_id:
|
||||
# crypt and bcrypt truncates passwords and would fail these tests.
|
||||
assert not AuthEncoding.pw_validate(enc, pw[:-2])
|
||||
assert not AuthEncoding.pw_validate(enc, pw[2:])
|
||||
|
||||
|
||||
@pytest.mark.parametrize('schema_id', AuthEncoding.listSchemes())
|
||||
def testBlankPassword(schema_id):
|
||||
pw = u''
|
||||
enc = AuthEncoding.pw_encrypt(pw, schema_id)
|
||||
assert enc != pw
|
||||
assert AuthEncoding.pw_validate(enc, pw)
|
||||
assert not AuthEncoding.pw_validate(enc, enc)
|
||||
assert not AuthEncoding.pw_validate(enc, u'xxx')
|
||||
|
||||
|
||||
def testUnencryptedPassword():
|
||||
# Sanity check
|
||||
pw = u'my-password'
|
||||
assert AuthEncoding.pw_validate(pw, pw)
|
||||
assert not AuthEncoding.pw_validate(pw, pw + u'asdf')
|
||||
|
||||
|
||||
def testEncryptWithNotSupportedScheme():
|
||||
with pytest.raises(ValueError) as err:
|
||||
AuthEncoding.pw_encrypt(u'asdf', 'MD1')
|
||||
assert 'Not supported: MD1' == str(err.value)
|
||||
|
||||
|
||||
def testEncryptAcceptsTextAndBinaryEncodingNames():
|
||||
assert (AuthEncoding.pw_encrypt(u'asdf', b'SHA') ==
|
||||
AuthEncoding.pw_encrypt(u'asdf', u'SHA'))
|
||||
File renamed without changes.
@@ -0,0 +1,348 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: BTrees
|
||||
Version: 4.5.1
|
||||
Summary: Scalable persistent object containers
|
||||
Home-page: https://github.com/zopefoundation/BTrees
|
||||
Author: Zope Foundation
|
||||
Author-email: zodb-dev@zope.org
|
||||
License: ZPL 2.1
|
||||
Platform: any
|
||||
Classifier: Development Status :: 6 - Mature
|
||||
Classifier: License :: OSI Approved :: Zope Public License
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.4
|
||||
Classifier: Programming Language :: Python :: 3.5
|
||||
Classifier: Programming Language :: Python :: 3.6
|
||||
Classifier: Programming Language :: Python :: 3.7
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Classifier: Framework :: ZODB
|
||||
Classifier: Topic :: Database
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Classifier: Operating System :: Microsoft :: Windows
|
||||
Classifier: Operating System :: Unix
|
||||
Provides-Extra: test
|
||||
Provides-Extra: ZODB
|
||||
Provides-Extra: docs
|
||||
Requires-Dist: persistent (>=4.1.0)
|
||||
Requires-Dist: zope.interface
|
||||
Provides-Extra: ZODB
|
||||
Requires-Dist: ZODB; extra == 'ZODB'
|
||||
Provides-Extra: docs
|
||||
Requires-Dist: Sphinx; extra == 'docs'
|
||||
Requires-Dist: repoze.sphinx.autointerface; extra == 'docs'
|
||||
Provides-Extra: test
|
||||
Requires-Dist: transaction; extra == 'test'
|
||||
Requires-Dist: zope.testrunner; extra == 'test'
|
||||
|
||||
``BTrees``: scalable persistent components
|
||||
===========================================
|
||||
|
||||
.. image:: https://travis-ci.org/zopefoundation/BTrees.svg?branch=master
|
||||
:target: https://travis-ci.org/zopefoundation/BTrees
|
||||
|
||||
.. image:: https://ci.appveyor.com/api/projects/status/github/zopefoundation/BTrees?branch=master&svg=true
|
||||
:target: https://ci.appveyor.com/project/mgedmin/BTrees
|
||||
|
||||
.. image:: https://coveralls.io/repos/github/zopefoundation/BTrees/badge.svg?branch=master
|
||||
:target: https://coveralls.io/github/zopefoundation/BTrees?branch=master
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/BTrees.svg
|
||||
:target: https://pypi.org/project/BTrees/
|
||||
:alt: Current version on PyPI
|
||||
|
||||
.. image:: https://img.shields.io/pypi/pyversions/BTrees.svg
|
||||
:target: https://pypi.org/project/BTrees/
|
||||
:alt: Supported Python versions
|
||||
|
||||
|
||||
This package contains a set of persistent object containers built around
|
||||
a modified BTree data structure. The trees are optimized for use inside
|
||||
ZODB's "optimistic concurrency" paradigm, and include explicit resolution
|
||||
of conflicts detected by that mechanism.
|
||||
|
||||
Please see `the Sphinx documentation <http://btrees.readthedocs.io/>`_ for further
|
||||
information.
|
||||
|
||||
|
||||
``BTrees`` Changelog
|
||||
====================
|
||||
|
||||
4.5.1 (2018-08-09)
|
||||
------------------
|
||||
|
||||
- Produce binary wheels for Python 3.7.
|
||||
|
||||
- Use pyproject.toml to specify build dependencies. This requires pip
|
||||
18 or later to build from source.
|
||||
|
||||
|
||||
4.5.0 (2018-04-23)
|
||||
------------------
|
||||
|
||||
- Add support for Python 3.6 and 3.7.
|
||||
- Drop support for Python 3.3.
|
||||
- Raise an ``ImportError`` consistently on Python 3 if the C extension for
|
||||
BTrees is used but the ``persistent`` C extension is not available.
|
||||
Previously this could result in an odd ``AttributeError``. See
|
||||
https://github.com/zopefoundation/BTrees/pull/55
|
||||
- Fix the possibility of a rare crash in the C extension when
|
||||
deallocating items. See https://github.com/zopefoundation/BTrees/issues/75
|
||||
- Respect the ``PURE_PYTHON`` environment variable at runtime even if
|
||||
the C extensions are available. See
|
||||
https://github.com/zopefoundation/BTrees/issues/78
|
||||
- Always attempt to build the C extensions, but make their success
|
||||
optional.
|
||||
- Fix a ``DeprecationWarning`` that could come from I and L objects in
|
||||
Python 2 in pure-Python mode. See https://github.com/zopefoundation/BTrees/issues/79
|
||||
|
||||
4.4.1 (2017-01-24)
|
||||
------------------
|
||||
|
||||
Fixed a packaging bug that caused extra files to be included (some of
|
||||
which caused problems in some platforms).
|
||||
|
||||
4.4.0 (2017-01-11)
|
||||
------------------
|
||||
|
||||
- Allow None as a special key (sorted smaller than all others).
|
||||
|
||||
This is a bit of a return to BTrees 3 behavior in that Nones are
|
||||
allowed as keys again. Other objects with default ordering are
|
||||
still not allowed as keys.
|
||||
|
||||
4.3.2 (2017-01-05)
|
||||
------------------
|
||||
|
||||
- Make the CPython implementation consistent with the pure-Python
|
||||
implementation and only check object keys for default comparison
|
||||
when setting keys. In Python 2 this makes it possible to remove keys
|
||||
that were added using a less restrictive version of BTrees. (In
|
||||
Python 3 keys that are unorderable still cannot be removed.)
|
||||
Likewise, all versions can unpickle trees that already had such
|
||||
keys. See: https://github.com/zopefoundation/BTrees/issues/53 and
|
||||
https://github.com/zopefoundation/BTrees/issues/51
|
||||
|
||||
- Make the Python implementation consistent with the CPython
|
||||
implementation and check object key identity before checking
|
||||
equality and performing comparisons. This can allow fixing trees
|
||||
that have keys that now have broken comparison functions. See
|
||||
https://github.com/zopefoundation/BTrees/issues/50
|
||||
|
||||
- Make the CPython implementation consistent with the pure-Python
|
||||
implementation and no longer raise ``TypeError`` for an object key
|
||||
(in object-keyed trees) with default comparison on ``__getitem__``,
|
||||
``get`` or ``in`` operations. Instead, the results will be a
|
||||
``KeyError``, the default value, and ``False``, respectively.
|
||||
Previously, CPython raised a ``TypeError`` in those cases, while the
|
||||
Python implementation behaved as specified.
|
||||
|
||||
Likewise, non-integer keys in integer-keyed trees
|
||||
will raise ``KeyError``, return the default and return ``False``,
|
||||
respectively, in both implementations. Previously, pure-Python
|
||||
raised a ``KeyError``, returned the default, and raised a
|
||||
``TypeError``, while CPython raised ``TypeError`` in all three cases.
|
||||
|
||||
4.3.1 (2016-05-16)
|
||||
------------------
|
||||
|
||||
- Packaging: fix password used to automate wheel creation on Travis.
|
||||
|
||||
4.3.0 (2016-05-10)
|
||||
------------------
|
||||
|
||||
- Fix unexpected ``OverflowError`` when passing 64bit values to long
|
||||
keys / values on Win64. See:
|
||||
https://github.com/zopefoundation/BTrees/issues/32
|
||||
|
||||
- When testing ``PURE_PYTHON`` environments under ``tox``, avoid poisoning
|
||||
the user's global wheel cache.
|
||||
|
||||
- Ensure that the pure-Python implementation, used on PyPy and when a C
|
||||
compiler isn't available for CPython, pickles identically to the C
|
||||
version. Unpickling will choose the best available implementation.
|
||||
This change prevents interoperability problems and database corruption if
|
||||
both implementations are in use. While it is no longer possible to
|
||||
pickle a Python implementation and have it unpickle to the Python
|
||||
implementation if the C implementation is available, existing Python
|
||||
pickles will still unpickle to the Python implementation (until
|
||||
pickled again). See:
|
||||
https://github.com/zopefoundation/BTrees/issues/19
|
||||
|
||||
- Avoid creating invalid objects when unpickling empty BTrees in a pure-Python
|
||||
environment.
|
||||
|
||||
- Drop support for Python 2.6 and 3.2.
|
||||
|
||||
4.2.0 (2015-11-13)
|
||||
------------------
|
||||
|
||||
- Add support for Python 3.5.
|
||||
|
||||
4.1.4 (2015-06-02)
|
||||
------------------
|
||||
|
||||
- Ensure that pure-Python Bucket and Set objects have a human readable
|
||||
``__repr__`` like the C versions.
|
||||
|
||||
4.1.3 (2015-05-19)
|
||||
------------------
|
||||
|
||||
- Fix ``_p_changed`` when removing items from small pure-Python
|
||||
BTrees/TreeSets and when adding items to small pure-Python Sets. See:
|
||||
https://github.com/zopefoundation/BTrees/issues/13
|
||||
|
||||
|
||||
4.1.2 (2015-04-07)
|
||||
------------------
|
||||
|
||||
- Suppress testing 64-bit values in OLBTrees on 32 bit machines.
|
||||
See: https://github.com/zopefoundation/BTrees/issues/9
|
||||
|
||||
- Fix ``_p_changed`` when adding items to small pure-Python
|
||||
BTrees/TreeSets. See:
|
||||
https://github.com/zopefoundation/BTrees/issues/11
|
||||
|
||||
|
||||
4.1.1 (2014-12-27)
|
||||
------------------
|
||||
|
||||
- Accomodate long values in pure-Python OLBTrees.
|
||||
|
||||
|
||||
4.1.0 (2014-12-26)
|
||||
------------------
|
||||
|
||||
- Add support for PyPy and PyPy3.
|
||||
|
||||
- Add support for Python 3.4.
|
||||
|
||||
- BTree subclasses can define ``max_leaf_size`` or ``max_internal_size``
|
||||
to control maximum sizes for Bucket/Set and BTree/TreeSet nodes.
|
||||
|
||||
- Detect integer overflow on 32-bit machines correctly under Python 3.
|
||||
|
||||
- Update pure-Python and C trees / sets to accept explicit None to indicate
|
||||
max / min value for ``minKey``, ``maxKey``. (PR #3)
|
||||
|
||||
- Update pure-Python trees / sets to accept explicit None to indicate
|
||||
open ranges for ``keys``, ``values``, ``items``. (PR #3)
|
||||
|
||||
|
||||
4.0.8 (2013-05-25)
|
||||
------------------
|
||||
|
||||
- Fix value-based comparison for objects under Py3k: addresses invalid
|
||||
merges of ``[OLI]OBTrees/OBuckets``.
|
||||
|
||||
- Ensure that pure-Python implementation of ``OOBTree.byValue`` matches
|
||||
semantics (reversed-sort) of C implementation.
|
||||
|
||||
|
||||
4.0.7 (2013-05-22)
|
||||
------------------
|
||||
|
||||
- Issue #2: compilation error on 32-bit mode of OS/X.
|
||||
|
||||
- Test ``PURE_PYTHON`` environment variable support: if set, the C
|
||||
extensions will not be built, imported, or tested.
|
||||
|
||||
|
||||
4.0.6 (2013-05-14)
|
||||
------------------
|
||||
|
||||
- Changed the ``ZODB`` extra to require only the real ``ZODB`` package,
|
||||
rather than the ``ZODB3`` metapackage: depending on the version used,
|
||||
the metapackage could pull in stale versions of **this** package and
|
||||
``persistent``.
|
||||
|
||||
- Fixed Python version check in ``setup.py``.
|
||||
|
||||
|
||||
4.0.5 (2013-01-15)
|
||||
------------------
|
||||
|
||||
- Fit the ``repr`` of bucket objects, which could contain garbage
|
||||
characters.
|
||||
|
||||
|
||||
4.0.4 (2013-01-12)
|
||||
------------------
|
||||
|
||||
- Emulate the (private) iterators used by the C extension modules from
|
||||
pure Python. This change is "cosmetic" only: it prevents the ZCML
|
||||
``zope.app.security:permission.zcml`` from failing. The emulated
|
||||
classes are **not** functional, and should be considered implementation
|
||||
details.
|
||||
|
||||
- Accomodate buildout to the fact that we no longer bundle a copy
|
||||
of 'persistent.h'.
|
||||
|
||||
- Fix test failures on Windows: no longer rely on overflows from
|
||||
``sys.maxint``.
|
||||
|
||||
|
||||
4.0.3 (2013-01-04)
|
||||
------------------
|
||||
|
||||
- Added ``setup_requires==['persistent']``.
|
||||
|
||||
|
||||
4.0.2 (2013-01-03)
|
||||
------------------
|
||||
|
||||
- Updated Trove classifiers.
|
||||
|
||||
- Added explicit support for Python 3.2, Python 3.3, and PyPy.
|
||||
Note that the C extensions are not (yet) available on PyPy.
|
||||
|
||||
- Python reference implementations now tested separately from the C
|
||||
verions on all platforms.
|
||||
|
||||
- 100% unit test coverage.
|
||||
|
||||
|
||||
4.0.1 (2012-10-21)
|
||||
------------------
|
||||
|
||||
- Provide local fallback for persistent C header inclusion if the
|
||||
persistent distribution isn't installed. This makes the winbot happy.
|
||||
|
||||
|
||||
4.0.0 (2012-10-20)
|
||||
------------------
|
||||
|
||||
Platform Changes
|
||||
################
|
||||
|
||||
- Dropped support for Python < 2.6.
|
||||
|
||||
- Factored ``BTrees`` as a separate distribution.
|
||||
|
||||
Testing Changes
|
||||
###############
|
||||
|
||||
- All covered platforms tested under ``tox``.
|
||||
|
||||
- Added support for continuous integration using ``tox`` and ``jenkins``.
|
||||
|
||||
- Added ``setup.py dev`` alias (installs ``nose`` and ``coverage``).
|
||||
|
||||
- Dropped dependency on ``zope.testing`` / ``zope.testrunner``: tests now
|
||||
run with ``setup.py test``.
|
||||
|
||||
Documentation Changes
|
||||
#####################
|
||||
|
||||
- Added API reference, generated via Spinx' autodoc.
|
||||
|
||||
- Added Sphinx documentation based on ZODB Guide (snippets are exercised
|
||||
via 'tox').
|
||||
|
||||
- Added ``setup.py docs`` alias (installs ``Sphinx`` and
|
||||
``repoze.sphinx.autointerface``).
|
||||
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
BTrees-4.5.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
BTrees-4.5.1.dist-info/METADATA,sha256=Nb2ZkIBPwlBQFnLSaGd_6XWqJwn1DIzl5dOR5nri1Mk,11329
|
||||
BTrees-4.5.1.dist-info/RECORD,,
|
||||
BTrees-4.5.1.dist-info/WHEEL,sha256=lx06sLWNl7U6OABNP9EWDqGNT2LbGyG1l5xyFnYYudo,109
|
||||
BTrees-4.5.1.dist-info/entry_points.txt,sha256=OZFBvh0wrCZW2J7tzw2NztqnLWwpv5WcriQ9x7FELPY,6
|
||||
BTrees-4.5.1.dist-info/top_level.txt,sha256=tyKTCytaCG_dQ7OVIUdgV-PZM9ltjveiOYk5u5FesbU,15
|
||||
BTrees/BTreeItemsTemplate.c,sha256=u5_bDWVQljKp87eX_FIQbm1HoVK9QztsB4UkcVZhVKU,24825
|
||||
BTrees/BTreeModuleTemplate.c,sha256=kO71qy4qU0nzS4PzTDzkvdn6cf-8DpzRFSt16WFp1O0,20611
|
||||
BTrees/BTreeTemplate.c,sha256=qJJnOLO9GJZNNzbBLRO1AxloA62cGDtC-2QFFnupbUY,71551
|
||||
BTrees/BucketTemplate.c,sha256=5sSFK-XD19B13bpIVN-rFS8TTcf6OCAYNecFbVdybqw,53068
|
||||
BTrees/Development.txt,sha256=IJCMs8N362vMCr4H67mznKIr5Lb5BuYh5YRBzHDq8xk,16958
|
||||
BTrees/IFBTree.py,sha256=xTd4UoaUmBhvf0wtco-_AZI2G_2bqymFWKRPDKIHX5g,3452
|
||||
BTrees/IIBTree.py,sha256=43-TgRVrwHKzhwZ7myrbRbvUfRIL-EpXWmhKmYfXuZs,3426
|
||||
BTrees/IOBTree.py,sha256=1PKMEHbm6Q0tOT-nEE66p6oiWUYtRXGs4ca6kVTtGck,2776
|
||||
BTrees/Interfaces.py,sha256=-KxR8M0K5NVfWcvKbo5HkcjHZmPQQ0OXvLxXoaysX08,17831
|
||||
BTrees/LFBTree.py,sha256=4qVsFCP6dm-ocZUBMTM97yNkI4MjB14xoBVJPnIpNLk,3453
|
||||
BTrees/LLBTree.py,sha256=EyzLlsd-vdy12c6tVr57dshtR7yBRSq4ovXLbWnMoXw,3446
|
||||
BTrees/LOBTree.py,sha256=yLR9OWzuytSDeb16vQjoJTCTpmZrAq1d5GMxXhRs9tk,2777
|
||||
BTrees/Length.py,sha256=JX5_JLeRIwh79j_r87GnjFosExLwrj8H2eBjdvfb2IY,1937
|
||||
BTrees/MergeTemplate.c,sha256=oLbW1QqeERrfnkg9YXfDUXU4I4OAJZ7jQ1OJcWQ7mqM,12070
|
||||
BTrees/OIBTree.py,sha256=KvFHcH_80Cxy_Qclv8SlGrUVWapudsSGEKsEhOfcvcE,3338
|
||||
BTrees/OLBTree.py,sha256=SXe4IJ0NOAfd3YJbV5L68VJkfdC3ZqzFOv58SRBXiKQ,3330
|
||||
BTrees/OOBTree.py,sha256=n2dZCvzq83FJZ45lTywvYBvT2ozhJZZDraS6jGDZUaA,2524
|
||||
BTrees/SetOpTemplate.c,sha256=T5hDNXFqSW6i1rKtCVErg6W-H8HOYkc5hCh1j6-8uW8,15571
|
||||
BTrees/SetTemplate.c,sha256=GIW_9986HcjjwCXG2XnDz_BNHgsygf1umnv3FD92Gr8,10119
|
||||
BTrees/TreeSetTemplate.c,sha256=z7sOs0RDVCgoufuDIiMb1oBKEKyJpgGtaUY063cF7ZE,8455
|
||||
BTrees/_IFBTree.c,sha256=BIJrf9LcDM_DRKCtnXJqoAnwvDwhnh_3x_l7CQWzZ3g,1136
|
||||
BTrees/_IFBTree.cpython-36m-darwin.so,sha256=-pDtbOXMyRLnyEzGPESPtNezHMVYjIkcI4_8LjbfQ90,186992
|
||||
BTrees/_IIBTree.c,sha256=DXzS4WGNkVYneiEGtX9F0olC750rxFQfcAVzUlaBCT0,1130
|
||||
BTrees/_IIBTree.cpython-36m-darwin.so,sha256=fY6YmOcdTiBl3DeGES-_KBdMLxDgCcGq7zFNfg8_dfc,182652
|
||||
BTrees/_IOBTree.c,sha256=nL6yr4-u6rPo_y8A8TD1irmPVG0t4szMVh4NKumypgI,1141
|
||||
BTrees/_IOBTree.cpython-36m-darwin.so,sha256=vNJgmpO6m0rYNxQfpSe5Qse1d5BNGEIovI72szY6Ogk,182500
|
||||
BTrees/_LFBTree.c,sha256=vZ8O4_6sYU54cSwbcyy1FXUfbypQzuE59tYN6Po10GE,1208
|
||||
BTrees/_LFBTree.cpython-36m-darwin.so,sha256=KuOsXfRQGAFZZjIKv9RCs_EEiiUXmrhZoVOSLZQQMms,187080
|
||||
BTrees/_LLBTree.c,sha256=P31gcA6clVlSgAlBLzJ4hqdZMPqwV6q9pKfEexXRH9Q,1199
|
||||
BTrees/_LLBTree.cpython-36m-darwin.so,sha256=WOhNkol3_nyCdjN7eUsLfz7hYw1ybbSi4Xz0AtvjmSc,186820
|
||||
BTrees/_LOBTree.c,sha256=-bq0twqbE0oqlxyMS6chYBR5ObvLvFQAa0IyFK-l4ro,1178
|
||||
BTrees/_LOBTree.cpython-36m-darwin.so,sha256=wLbc18-MMpOeFIrdQVm932uKHq-nb_2h3c25OfOieO4,182588
|
||||
BTrees/_OIBTree.c,sha256=6SLJqZskZHEQB4OqCIlZZwGRwADi7MOvu-8W3hRJBo4,1141
|
||||
BTrees/_OIBTree.cpython-36m-darwin.so,sha256=E4ToIjjUlcb1BXQ2XexI17hzxGpLkAhzFdTjZoOi4hA,178356
|
||||
BTrees/_OLBTree.c,sha256=Hu0ylTuFWEPivGsL0ClS1YLdvx3fTIS9phtMpSt9zXo,1178
|
||||
BTrees/_OLBTree.cpython-36m-darwin.so,sha256=qoKSvSbbNErXIMNVKYxyapIqDRNiU9M7VSXNxDE19m4,178428
|
||||
BTrees/_OOBTree.c,sha256=e-Wd39TQyfwnX9X-o1mp9S_hIUpWGmUjmGvdH4f3__Q,1150
|
||||
BTrees/_OOBTree.cpython-36m-darwin.so,sha256=7jOL1UtqyRz7YKvmBGma5asRslm4GlRKpf9sLxteCEk,174148
|
||||
BTrees/__init__.py,sha256=SuUBN3IfVFkSbKLece09uEDFg76AwWWD2qx37AaYXxg,1871
|
||||
BTrees/__pycache__/IFBTree.cpython-36.pyc,,
|
||||
BTrees/__pycache__/IIBTree.cpython-36.pyc,,
|
||||
BTrees/__pycache__/IOBTree.cpython-36.pyc,,
|
||||
BTrees/__pycache__/Interfaces.cpython-36.pyc,,
|
||||
BTrees/__pycache__/LFBTree.cpython-36.pyc,,
|
||||
BTrees/__pycache__/LLBTree.cpython-36.pyc,,
|
||||
BTrees/__pycache__/LOBTree.cpython-36.pyc,,
|
||||
BTrees/__pycache__/Length.cpython-36.pyc,,
|
||||
BTrees/__pycache__/OIBTree.cpython-36.pyc,,
|
||||
BTrees/__pycache__/OLBTree.cpython-36.pyc,,
|
||||
BTrees/__pycache__/OOBTree.cpython-36.pyc,,
|
||||
BTrees/__pycache__/__init__.cpython-36.pyc,,
|
||||
BTrees/__pycache__/_base.cpython-36.pyc,,
|
||||
BTrees/__pycache__/_compat.cpython-36.pyc,,
|
||||
BTrees/__pycache__/check.cpython-36.pyc,,
|
||||
BTrees/__pycache__/fsBTree.cpython-36.pyc,,
|
||||
BTrees/__pycache__/utils.cpython-36.pyc,,
|
||||
BTrees/_base.py,sha256=h6CFY1XeQHNJ9lkH6UWwMSTkTWOoOXNLUdUqvNbo1O4,49411
|
||||
BTrees/_compat.h,sha256=7Juyq0L7R692-QxH7QDk3HD7AA3N0eAnwfP4zoqoGJg,1392
|
||||
BTrees/_compat.py,sha256=30krwQo7chtAhl6V-LY0G4723rA43bZSHiERonPCHQc,2902
|
||||
BTrees/_fsBTree.c,sha256=R2xeZeyvlUvJObF-66R2HJOFoPHLO87p3rVpe9byssY,4805
|
||||
BTrees/_fsBTree.cpython-36m-darwin.so,sha256=3YzUd8gVpOREfkVJzM2NaY_cIYgZgmCULvLXSv01Rg8,174228
|
||||
BTrees/check.py,sha256=73Wkf_42KfDQ_LjUlTC9hYC_v3e2gUXOJFkGbqwAAXM,15481
|
||||
BTrees/floatvaluemacros.h,sha256=8--_OkpCuflybs5jaP3B54BWxw38u8vESph4IM545AI,899
|
||||
BTrees/fsBTree.py,sha256=r1_iTqRLCBqKGPPsvj1D0mYoRzN85amNnrJJbjiHWj0,3185
|
||||
BTrees/intkeymacros.h,sha256=M0lCFColrnPHK6qRbbgwqwAITplrCVfIDCcHp7bSE-I,1547
|
||||
BTrees/intvaluemacros.h,sha256=oL_1993h7sS6O716DaKHytbC094xcBO4L1llPqX20Mo,1704
|
||||
BTrees/objectkeymacros.h,sha256=BGhqG4nV122anWw1CNJE3dj2c5LhqKwDcvvx-Y_8QE0,1285
|
||||
BTrees/objectvaluemacros.h,sha256=duuNoUjv-IwKbzEVxZjvvmDCETmzzASeQp1N2188BuM,460
|
||||
BTrees/sorters.c,sha256=_RFLxqdW3ZhfJnMfo7tS0cQ1OuftmTmdwMLoJmH29p4,15218
|
||||
BTrees/tests/__init__.py,sha256=as-9vgC96TSaF9bHM7EBWBANqSJOgJjwWtUT3lvHQZg,52
|
||||
BTrees/tests/__pycache__/__init__.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/common.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/testBTrees.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/testBTreesUnicode.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/testConflict.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/test_IFBTree.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/test_IIBTree.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/test_IOBTree.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/test_LFBTree.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/test_LLBTree.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/test_LOBTree.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/test_Length.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/test_OIBTree.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/test_OLBTree.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/test_OOBTree.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/test__base.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/test_btreesubclass.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/test_check.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/test_fsBTree.cpython-36.pyc,,
|
||||
BTrees/tests/__pycache__/test_utils.cpython-36.pyc,,
|
||||
BTrees/tests/common.py,sha256=ypzQE17QBOIpZNQmiRBtLMUA3nN68ZpMsjhjcnJmrhU,86610
|
||||
BTrees/tests/testBTrees.py,sha256=9kHPN0-V9ZTYE05-KPocMChxWsrG3YtdGDxy_wfmZAg,17407
|
||||
BTrees/tests/testBTreesUnicode.py,sha256=mPQraEu9VPV4mDlMcJRhpKJC0hvK2-IwJ-aZASP-DsM,2554
|
||||
BTrees/tests/testConflict.py,sha256=O6bjf7ApdPaYzYCpmPcMC4yoEeS07dfvO280sKuNBZU,21323
|
||||
BTrees/tests/test_IFBTree.py,sha256=lDac4rWXBtzaIYcbWWPcEshJKvLlwcJRzPzpltUC4rU,10641
|
||||
BTrees/tests/test_IIBTree.py,sha256=ois9MwkJ33ZoryShqIRt6FE51rGPwBRT-fw8ceoZtmo,14197
|
||||
BTrees/tests/test_IOBTree.py,sha256=LwwX727SNAWCf3tP18ZdY1rxNIYUseCKP2O1I860QE0,11531
|
||||
BTrees/tests/test_LFBTree.py,sha256=RE2Fwo1jPPhSE4WI5R8Q0Q65wyRRydEJ5wMKcBcLK2w,8957
|
||||
BTrees/tests/test_LLBTree.py,sha256=ECYj7Fn_em3RMwpd7PYb7Na5IR0FM5_lkrFbP1IkjP8,11760
|
||||
BTrees/tests/test_LOBTree.py,sha256=RnAkGsl6prphDGpd-twb562MDlhYnn8Ka_EagQb1sEI,10124
|
||||
BTrees/tests/test_Length.py,sha256=gyEXtVvSw7O_AMA9Yd2usemR_Qgie3sdr4lsCjkM0wY,3502
|
||||
BTrees/tests/test_OIBTree.py,sha256=eeB1T_nlMb5DQMbD1ASmEwj-TEC7Pb8fSXwpVh-nyEU,10947
|
||||
BTrees/tests/test_OLBTree.py,sha256=Bm6QqM9NdoqhrRqRykjurAqO9Sg8YzUQ4BrZWA8cc8A,10293
|
||||
BTrees/tests/test_OOBTree.py,sha256=bfnhr0zQzvQVMW9FtL1QWT6J38Lt-b1nVYC4r7hZrS8,12573
|
||||
BTrees/tests/test__base.py,sha256=7teTiKJfi-jc-SG1RL4KVhAYmy_H6oC-bCjY3J-2I2Q,114377
|
||||
BTrees/tests/test_btreesubclass.py,sha256=bT0TwSCViQGoG8hRSzNLC6VAw3wlzaP1n80OZGjwREA,1646
|
||||
BTrees/tests/test_check.py,sha256=UdeT_QGMF5ole6fya4853XcxrJSzeW3GSnz2J4RmngQ,12948
|
||||
BTrees/tests/test_fsBTree.py,sha256=88hNt0wIFTizjPaUgHkz2msFO6-eFPOyHSEQKZKci-0,2136
|
||||
BTrees/tests/test_utils.py,sha256=8B0lqFwYoHZalmEUyogHfDlN6IoERBaPjlr0TD-xu50,2703
|
||||
BTrees/utils.py,sha256=Vnpv1X63hp3aBPUeS7EPuZo0NoGCBmuogfu8pAcLgSk,1442
|
||||
terryfy/__init__.py,sha256=RBtPV4__9gzLYGnKiTMv1tGSXLxzFpIuVjARdyHHi0w,31
|
||||
terryfy/__pycache__/__init__.cpython-36.pyc,,
|
||||
terryfy/__pycache__/bdist_wheel.cpython-36.pyc,,
|
||||
terryfy/__pycache__/cp_suff_real_libs.cpython-36.pyc,,
|
||||
terryfy/__pycache__/fuse_suff_real_libs.cpython-36.pyc,,
|
||||
terryfy/__pycache__/monkeyexec.cpython-36.pyc,,
|
||||
terryfy/__pycache__/repath_lib_names.cpython-36.pyc,,
|
||||
terryfy/__pycache__/test_travisparse.cpython-36.pyc,,
|
||||
terryfy/__pycache__/travisparse.cpython-36.pyc,,
|
||||
terryfy/__pycache__/wafutils.cpython-36.pyc,,
|
||||
terryfy/bdist_wheel.py,sha256=uMS-xIbyD81dC8nyKh6NuFNA3qVWY6TVXyzzsV5DBTc,811
|
||||
terryfy/cp_suff_real_libs.py,sha256=11dwW6AePQ2sVB0C4wurs-tr4z1ytRgiHz_PsXGpFiw,720
|
||||
terryfy/fuse_suff_real_libs.py,sha256=wfsxzciiEf1FgTga7MSJ0KXsulUyWvYaul5Z4lIfM0E,1099
|
||||
terryfy/monkeyexec.py,sha256=QFZ5IB5JwsJK-Pc7IFnwrOD1pygE812zYn98kV-6V8A,1708
|
||||
terryfy/repath_lib_names.py,sha256=kv2dHTRRYHjIwNbcfbFNna_6dHC6yyd-orO2BWMfNOk,1018
|
||||
terryfy/test_travisparse.py,sha256=eGxYZSYdzwkxI6B9oYhZB-iGu4ifVla_F4i3Nkq7efo,2148
|
||||
terryfy/travisparse.py,sha256=Io2vjJJz6iBHtSqZGMUm0YZ8RUO3d4y06bgYMC0qWT4,1763
|
||||
terryfy/wafutils.py,sha256=FIxHuY991jWwdrGB_PVjSHLf3aeZpqKWoK_9rJbH8Vk,9118
|
||||
@@ -0,0 +1,5 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.31.1)
|
||||
Root-Is-Purelib: false
|
||||
Tag: cp36-cp36m-macosx_10_6_intel
|
||||
|
||||
Loaded 100 of 3163 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user