def render(self, context): start = get_var(self.start, context) end = get_var(self.end, context) delta = end - start days = delta.days hours, remainder = divmod(delta.seconds, 3600) minutes, remainder = divmod(remainder, 60) seconds = remainder human_delta = '' if days > 0: if len(human_delta) > 0: human_delta += ', ' human_delta += '%i day%s' % (days, pluralize(days)) if hours > 0: if len(human_delta) > 0: human_delta += ', ' human_delta += '%i hour%s' % (hours, pluralize(hours)) if minutes > 0: if len(human_delta) > 0: human_delta += ', ' human_delta += '%i minute%s' % (minutes, pluralize(minutes)) if seconds > 0: if len(human_delta) > 0: human_delta += ', ' human_delta += '%i second%s' % (seconds, pluralize(seconds)) return human_delta
def calculate_time_since(then): from datetime import datetime, timedelta from django.template.defaultfilters import pluralize, date as formatdate if not then: return "unknown" now = datetime.now() if then >= now: return "just now" diff = now - then if diff.days > 7: if now.year == then.year: return formatdate(then, "M d") else: return formatdate(then, "M d, Y") elif diff.days > 1: return "%s" % (formatdate(then, "l")) elif diff.days == 1: return "yesterday" seconds = diff.seconds minutes = seconds/60 hours = minutes/60 if hours >= 1: return "%s hour%s ago" % (str(hours), pluralize(hours)) if minutes >= 1: return "%s minute%s ago" % (str(minutes), pluralize(minutes)) return "%s second%s ago" % (str(seconds), pluralize(seconds))
def humanize_duration(duration): """ Returns a humanized string representing time difference For example: 2 days 1 hour 25 minutes 10 seconds """ days = duration.days hours = int(duration.seconds / 3600) minutes = int(duration.seconds % 3600 / 60) seconds = int(duration.seconds % 3600 % 60) parts = [] if days > 0: parts.append(u'%s %s' % (days, pluralize(days, _('day,days')))) if hours > 0: parts.append(u'%s %s' % (hours, pluralize(hours, _('hour,hours')))) if minutes > 0: parts.append(u'%s %s' % (minutes, pluralize(minutes, _('minute,minutes')))) if seconds > 0: parts.append(u'%s %s' % (seconds, pluralize(seconds, _('second,seconds')))) return ', '.join(parts) if len(parts) != 0 else _('< 1 second')
def handle(self, **options): event_list = self.spektrix\ .GetAllInstancesFromAllAttributes(datetime(2011,1,1)) # Get / create event for lxml_event in event_list.getchildren(): # Hit spektrix again, as they don't actually supply all the Event attributes # in the GetNextAllAttributes full_lxml_event = self.spektrix.GetEventAllAttributes(lxml_event.Id) for key in [u'Attributes']: if key in full_lxml_event: del(full_lxml_event[key]) event, created, updated = self.event_model\ .spektrix.update_or_create(full_lxml_event) if created: self.new_events +=1 if updated: self.events_edited +=1 # Get / Create attributes save_attributes(event, full_lxml_event) # get / create event times for event for lxml_time in full_lxml_event.Times.getchildren(): time, created, updated = self.time_model\ .spektrix.update_or_create(lxml_time, event=event) # Get / Create attributes save_attributes(time, lxml_time) print "%i Event%s updated" % (self.events_edited, pluralize(self.events_edited)) print "%i Event%s created" % (self.new_events, pluralize(self.new_events))
def humanize_timesince(date): """Converts ``date`` to a human readable string describing the time since :param date: Date to convert :returns: Time since string :rtype: string """ delta = datetime.datetime.now() - date num_years = delta.days // 365 if num_years > 0: return u"%d year%s ago" % (num_years, pluralize(num_years)) num_weeks = delta.days // 7 if num_weeks > 0: return u"%d week%s ago" % (num_weeks, pluralize(num_weeks)) if delta.days > 0: return u"%d day%s ago" % (delta.days, pluralize(delta.days)) num_hours = delta.seconds // 3600 if num_hours > 0: return u"%d hour%s ago" % (num_hours, pluralize(num_hours)) num_minutes = delta.seconds // 60 if num_minutes > 0: return u"%d minute%s ago" % (num_minutes, pluralize(num_minutes)) return u"a few seconds ago"
def process_import(self, request, *args, **kwargs): ''' Perform the actual import action (after the user has confirmed he wishes to import) ''' opts = self.model._meta resource = self.get_import_resource_class()() confirm_form = ConfirmImportForm(request.POST) if confirm_form.is_valid(): import_formats = self.get_import_formats() input_format = import_formats[ int(confirm_form.cleaned_data['input_format']) ]() tmp_storage = self.get_tmp_storage_class()(name=confirm_form.cleaned_data['import_file_name']) data = tmp_storage.read(input_format.get_read_mode()) if not input_format.is_binary() and self.from_encoding: data = force_text(data, self.from_encoding) dataset = input_format.create_dataset(data) result = resource.import_data(dataset, dry_run=False, raise_errors=True, file_name=confirm_form.cleaned_data['original_file_name'], user=request.user) if not self.get_skip_admin_log(): # Add imported objects to LogEntry logentry_map = { RowResult.IMPORT_TYPE_NEW: ADDITION, RowResult.IMPORT_TYPE_UPDATE: CHANGE, RowResult.IMPORT_TYPE_DELETE: DELETION, } content_type_id = ContentType.objects.get_for_model(self.model).pk for row in result: if row.import_type != row.IMPORT_TYPE_SKIP: LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=content_type_id, object_id=row.object_id, object_repr=row.object_repr, action_flag=logentry_map[row.import_type], change_message="%s through import_export" % row.import_type, ) success_message = u'Import finished, with {} new {}{} and ' \ u'{} updated {}{}.'.format(result.totals[RowResult.IMPORT_TYPE_NEW], opts.model_name, pluralize(result.totals[RowResult.IMPORT_TYPE_NEW]), result.totals[RowResult.IMPORT_TYPE_UPDATE], opts.model_name, pluralize(result.totals[RowResult.IMPORT_TYPE_UPDATE])) messages.success(request, success_message) tmp_storage.remove() post_import.send(sender=None, model=self.model) url = reverse('admin:%s_%s_changelist' % self.get_model_info(), current_app=self.admin_site.name) return HttpResponseRedirect(url)
def add_collection_relations(self, request): from django.forms.formsets import formset_factory from django.template.defaultfilters import capfirst, pluralize CollectionFormSet = formset_factory(CollectionRelationForm, extra=4) form = ContentTypeForm(request.GET) formset = CollectionFormSet() if request.method == "POST": formset = CollectionFormSet(request.POST) form = ContentTypeForm(request.POST) if form.is_valid(): try: ct = ContentType.objects.get(pk=form.cleaned_data.get('ct')) except ContentType.DoesNotExist: raise Http404 else: # The form is invalid, which should never happen (even on initial GET). # TODO: Should I raise 404 or redirect? raise Http404 if formset.is_bound and formset.is_valid(): ids = form.cleaned_data.get('ids').split(',') objects = ct.model_class()._default_manager.filter(pk__in=ids) num_collections = 0 for c_form in formset.forms: collection_id = c_form.cleaned_data.get('collection', None) if collection_id is not None: collection = Collection.objects.get(pk=collection_id) for obj in objects: cr = CollectionRelation.objects.create(content_object=obj, collection=collection) collection.collectionrelation_set.add(cr) num_collections += 1 redir_url = '%sadmin_%s_%s_changelist' % ( self.admin_site.name, ct.model_class()._meta.app_label, ct.model_class()._meta.module_name) request.user.message_set.create( message='%s %s%s successfully added to the selected %s%s.' % ( len(objects), capfirst(ct.model_class()._meta.verbose_name), pluralize(len(objects)), capfirst(Collection._meta.verbose_name), pluralize(num_collections) )) return HttpResponseRedirect(reverse(redir_url)) t = loader.get_template('admin/massmedia/add_collection_relations.html') c = RequestContext(request, { 'ct_opts': ct.model_class()._meta, 'collection_opts': Collection._meta, 'formset': formset, 'form': form, 'media': form.media + formset.media }) return HttpResponse(t.render(c))
def show_update_message(self, request, queryset): count = queryset.count() message = '{amount} {model}{s} {plural} updated.'.format( amount = count, model = queryset.model.__name__.lower(), s = pluralize(count), plural = pluralize(count, 'was,were') ) self.message_user(request, message)
def update_tags(request, obj, comment, person, set_tags=[], reset_tags=[], extra_notify=[]): if settings.USE_DB_REDESIGN_PROXY_CLASSES: doc = Document.objects.get(pk=obj.pk) save_document_in_history(doc) obj.tags.remove(*reset_tags) obj.tags.add(*set_tags) doc.time = datetime.datetime.now() e = DocEvent(type="changed_document", time=doc.time, by=person, doc=doc) l = [] if set_tags: l.append(u"Annotation tag%s %s set." % (pluralize(set_tags), ", ".join(x.name for x in set_tags))) if reset_tags: l.append(u"Annotation tag%s %s cleared." % (pluralize(reset_tags), ", ".join(x.name for x in reset_tags))) e.desc = " ".join(l) e.save() receivers = get_notification_receivers(doc, extra_notify) send_mail(request, receivers, settings.DEFAULT_FROM_EMAIL, u"Annotations tags changed for draft %s" % doc.name, 'ietfworkflows/annotation_tags_updated_mail.txt', dict(doc=doc, entry=dict(setted=", ".join(x.name for x in set_tags), unsetted=", ".join(x.name for x in reset_tags), change_date=doc.time, person=person, comment=comment))) return ctype = ContentType.objects.get_for_model(obj) setted = [] resetted = [] for tag in set_tags: if isinstance(tag, basestring): if set_tag_by_name(obj, tag): setted.append(tag) else: if set_tag(obj, tag): setted.append(tag.name) for tag in reset_tags: if isinstance(tag, basestring): if reset_tag_by_name(obj, tag): resetted.append(tag) else: if reset_tag(obj, tag): resetted.append(tag.name) entry = ObjectAnnotationTagHistoryEntry.objects.create( content_type=ctype, content_id=obj.pk, setted=','.join(setted), unsetted=','.join(resetted), date=datetime.datetime.now(), comment=comment, person=person) notify_tag_entry(entry, extra_notify)
def _preadjust(self): empty_count = 0 skipped_count = 0 remaining_count = 0 helpers = self._get_helpers() for helper in helpers: empty_count += len([info_dict for info_dict in six.itervalues(helper.adjusted) if not info_dict]) skipped_count += len([info_dict for info_dict in six.itervalues(helper.adjusted) if info_dict and 'ajax_url' not in info_dict]) remaining_count += len(helper.adjusted) - skipped_count - empty_count self.stdout.write( "Skipped {0} empty path{1}.\n".format( empty_count, pluralize(empty_count))) self.stdout.write( "Skipped {0} path{1} which ha{2} already been adjusted.\n".format( skipped_count, pluralize(skipped_count), pluralize(skipped_count, 's,ve'))) if remaining_count == 0: self.stdout.write("No paths remaining to adjust.\n") else: self.stdout.write("Adjusting {0} path{1}... ".format( remaining_count, pluralize(remaining_count))) self.stdout.flush() failed_count = 0 for helper in helpers: remaining = {} for item, info_dict in six.iteritems(helper.adjusted): # Skip if missing if not info_dict: continue # Skip if already adjusted if 'ajax_url' not in info_dict: continue remaining.setdefault(helper.lookup_func(item, None), []).append(item) for path, items in six.iteritems(remaining): try: helper._generate(path) except IOERRORS: failed_count += 1 self.stdout.write("Done.\n") if failed_count: self.stdout.write( "{0} path{1} failed due to I/O errors.".format( failed_count, pluralize(failed_count)))
def add_success_message(self, result, request): opts = self.model._meta success_message = u'Import finished, with {} new {}{} and ' \ u'{} updated {}{}.'.format(result.totals[RowResult.IMPORT_TYPE_NEW], opts.model_name, pluralize(result.totals[RowResult.IMPORT_TYPE_NEW]), result.totals[RowResult.IMPORT_TYPE_UPDATE], opts.model_name, pluralize(result.totals[RowResult.IMPORT_TYPE_UPDATE])) messages.success(request, success_message)
def handle(self, **options): for app in models.get_apps(): for model in models.get_models(app): objects_quantity = model.objects.count() str_for_out = "Model {0} has {1} object{2}" print str_for_out.format(model.__name__, objects_quantity, pluralize(objects_quantity)) str_for_err = "error: Model {0} has {1} object{2}\n" sys.stderr.write(str_for_err.format(model.__name__, objects_quantity, pluralize(objects_quantity) ) )
def _message_user_about_update(self, request, rows_updated, verb): """Send message about action to user. `verb` should shortly describe what have changed (e.g. 'enabled'). """ self.message_user( request, _('{0} task{1} {2} successfully {3}').format( rows_updated, pluralize(rows_updated), pluralize(rows_updated, _('was,were')), verb, ), )
def module_duration(self): duration = int() classes = self.classes.select_related() for klass in classes: duration += klass.time result = duration / 60 return _(u"{0} hora{1}/aula".format(result, pluralize(result)))
def clean(self, value): if not value and self.required: raise forms.ValidationError(self.error_messages['required']) if value and self.max_choices and len(value) > self.max_choices: raise forms.ValidationError(u'Você deve selecionar no máximo %s escolha%s.' % (apnumber(self.max_choices), pluralize(self.max_choices))) return value
def compare(self, name, form_data): if self.original and self.required: # run compare only for original fields # do not run compare for hidden fields (they are not required) if form_data.get(name) != form_data.get(self.get_clone_name(name)): raise forms.ValidationError(_(u"{0}{1} don't match").format( self.label, defaultfilters.pluralize(2)))
def _type_helper(o): if isinstance(o, Model): return "%s.%s" % o._meta.app_label, o._meta.object_name.lower() elif isinstance(o, (list, dict, set, QuerySet)): return "%s (%s item%s)" % (str(type(o)), len(o), pluralize(len(o))) else: return str(type(o))
def render_actors(actors): """ Gives the following experience 1 actor - SomeBody commented on X 2 actors - SomeBody and AnotherPerson commented on X >2 actors - SomeBody, AnotherPerson and 3 others commented on X """ # http://stackoverflow.com/questions/11092511/python-list-of-unique-dictionaries unique_actors = map(dict, set(tuple(sorted(d.items())) for d in actors)) # But we need them in the original order since its timestamped unique_redux = [] for actor in actors: for unique in unique_actors: if unique == actor and unique not in unique_redux: unique_redux.append(unique) break actors = unique_redux join_on = ", " if len(actors) == 2: join_on = " and " string = join_on.join(i["displayName"] for i in actors[:2]) if len(actors) > 2: string = "%s and %s other%s" % (string, len(actors) - 2, pluralize(len(actors) - 2)) return string
def natural_seconds(seconds, abbreviate=False): '''Custom template tag to display integer seconds as HH hours, MM minutes, SS seconds. Partially inspired by the filters in :mod:`django.contrib.humanize`. ''' # don't error if we got an empty/invalid value if not seconds: return '' duration = datetime.timedelta(seconds=int(seconds)) duration_time = datetime.datetime(1, 1, 1) + duration time_vals = [] fields = ['hour', 'minute', 'second'] # only display values that are non-zero if abbreviate: labels = {'hour': 'hr', 'minute': 'min', 'second': 'sec'} else: labels = {'hour': 'hour', 'minute': 'minute', 'second': 'second'} for dur in fields: val = getattr(duration_time, dur) if val: time_vals.append('%d %s%s' % (val, labels[dur], pluralize(val))) return ', '.join(time_vals)
def org_spending_section(entity_id, name, cycle, totals): section = { 'name': 'Federal Spending', 'template': 'org_grants_and_contracts.html', } spending = api.org.fed_spending(entity_id, cycle) filter_bad_spending_descriptions(spending) section['grants_and_contracts'] = spending section['gc_links'] = external_sites.get_gc_links(name.__str__(), cycle) gc_found_things = [] for gc_type in ['grant', 'contract', 'loan']: if totals.get('%s_count' % gc_type, 0): gc_found_things.append('%s %s%s' % ( intcomma(totals['%s_count' % gc_type]), gc_type, pluralize(totals['%s_count' % gc_type]) )) section['gc_found_things'] = gc_found_things return section
def clean(self, value): if not value and self.required: raise forms.ValidationError(self.error_messages['required']) if value and self.max_choices and len(value) > self.max_choices: raise forms.ValidationError('You must select a maximum of %s choice%s.' % (apnumber(self.max_choices), pluralize(self.max_choices))) return value
def l_trackers(self, item): count = item.sighting_tracking.count() if count == 0: return "No trackers" else: return (u"<a href='../sightingtracking/?sighting__id={0}'>{1} tracker{2}</a>" .format(item.pk, count, pluralize(count)))
def handle_noargs(self, **options): # Clear all adjusted images that reference nonexistant # storage paths. self._delete_queryset(self._old_adjustments()) # Clear all areas that reference nonexistant storage paths. self._delete_queryset(self._old_areas()) # Clear all adjusted images that reference nonexistant adjustments. self._delete_queryset(self._missing_adjustments(), 'reference missing adjustments') # Clear all duplicate adjusted images. self._delete_queryset(self._duplicate_adjustments(), reason='is a duplicate', reason_plural='are duplicates') # Clean up files that aren't referenced by any adjusted images. orphans = self._orphaned_files() if not orphans: self.stdout.write("No orphaned files found.\n") else: self.stdout.write( "Deleting {0} orphaned file{1}... ".format( len(orphans), pluralize(len(orphans)))) self.stdout.flush() for filepath in orphans: try: default_storage.delete(filepath) except IOERRORS: pass self.stdout.write("Done.\n") self.stdout.write("\n")
def reputation(user): """ Creates a ``<span>`` for a User's reputation score and for each type of badge they hold. This tag can accept a User object, or a dict containing the appropriate values. """ try: reputation, gold, silver, bronze = (user['reputation'], user['gold'], user['silver'], user['bronze']) except (TypeError, AttributeError, KeyError): reputation, gold, silver, bronze = (user.reputation, user.gold, user.silver, user.bronze) spans = [REPUTATION_TEMPLATE % intcomma(reputation)] for badge, count in zip(Badge.TYPE_CHOICES, (gold, silver, bronze)): if not count: continue spans.append(BADGE_TEMPLATE % { 'id': badge[0], 'name': badge[1], 'count': count, 'plural': pluralize(count), }) return mark_safe(u''.join(spans))
def issues_set_status(request, project_number): project = get_project(project_number) r = re.compile(r'issue-(\d+)') if not request.POST.has_key("status_id"): messages.error(request, "Det skjedde en feil under statusoppdateringen.") else: status_id = request.POST["status_id"] status = IssueStatus.objects.get(id=status_id) altered = [] for field, value in request.POST.iteritems(): m = r.match(field) if value == "on" and m: issue_id = m.groups()[0] issue = get_object_or_404(Issue, id=issue_id) issue.status = status issue.save() altered.append(issue) if status.closed: verb = u"lukket" elif status.name == "on_hold": verb = u"satt på vent" elif status.name == "wip": verb = u"endret til 'under behandling'" else: verb = u"åpnet" messages.success(request, "%d sak%s ble %s." % (len(altered), pluralize(altered, "er"), verb)) return HttpResponseRedirect(project.get_absolute_url())
def minutes_as_days_hours_mins(self, minutes): """Format a number of minutes as days, hours, minutes, only showing the values we need to. Taken from: http://stackoverflow.com/questions/4048651/python-function-to-convert-seconds-into-minutes-hours-and-days with some adjustments.""" if minutes is None: return "" td = timedelta(minutes=minutes) d = datetime(1,1,1) + td if d.day-1 > 0: return "%d day%s, %d hour%s, %d minute%s" % (d.day-1, pluralize(d.day-1), d.hour, pluralize(d.hour), d.minute, pluralize(d.minute)) elif d.hour > 0: return "%d hour%s, %d minute%s" % (d.hour, pluralize(d.hour), d.minute, pluralize(d.minute)) else: return "%d minute%s" % (d.minute, pluralize(d.minute))
def plural(text, seq, arg=u's'): "Similar to pluralize, but looks at the text, too" from django.template.defaultfilters import pluralize if text.endswith('s'): return text else: return text + pluralize(len(seq), arg)
def clean_role(self): role = self.cleaned_data['role'] # Nothing to check if they aren't being set to admin. if role != 'admin': return role # Nothing to check if there is no admin limit. if self.tier.admin_limit is None: return role # Nothing to check if the user is already an admin. if 'role' not in self.changed_data: return role # And finally, we're good if there's room for another admin. admin_count = self.site_settings.admins.exclude(is_superuser=True ).exclude(is_active=False ).count() if (admin_count + 1) <= self.tier.admin_limit: return role # For backwards-compatibility, pretend the site owner (a # superuser) counts toward the limit. limit = self.tier.admin_limit + 1 raise ValidationError("You already have {limit} admin{s} in your " "site. Upgrade to have access to more.".format( limit=limit, s=pluralize(limit)))
def get_row_str_fields(self, obj, row=None): str_fields = super().get_row_str_fields(obj, row) if str_fields is None: str_fields = {} # Add formatted display of virtual field. is_plural = pluralize(row['exists_days'], arg='days') str_fields['exists_days'] = '{} {}'.format(row['exists_days'], 'day' if is_plural == '' else is_plural) return str_fields
def create_version(self, request, queryset): """ Create new versions of selected pages. """ for model in queryset: self.create_page_version(model) versions_created = len(queryset) self.message_user(request, '{0} version{1} created'.format(versions_created, defaultfilters.pluralize(versions_created)))
def get_type(self): jrs = int(self.array_infos.get("ls-jrs")) return _("Lecture seule temporaire ({0} jour{1})").format( jrs, pluralize(jrs))
def get_detail(self): jrs = int(self.array_infos.get("ban-jrs")) return _( "vous ne pouvez plus vous connecter sur {0} pendant {1} jour{2}." ).format(settings.ZDS_APP["site"]["literal_name"], jrs, pluralize(jrs))
def data_group_detail(request, pk, template_name="data_group/datagroup_detail.html"): dg = get_object_or_404(DataGroup, pk=pk) tabledata = { "fsid": dg.fs_id, "boolComp": dg.is_composition, "boolHab": dg.is_habits_and_practices, "boolSD": dg.is_supplemental_doc, "numregistered": dg.registered_docs(), "nummatched": dg.matched_docs(), "numextracted": dg.extracted_docs(), } context = { "datagroup": dg, "tabledata": tabledata, "clean_comp_data_fieldnames": ", ".join([ "ExtractedChemical_id" if x == "id" else x for x in dg.get_clean_comp_data_fieldnames() ]), "product_data_fieldnames": ", ".join([ "ExtractedChemical_id" if x == "id" else x for x in dg.get_product_template_fieldnames() ]), "uploaddocs_form": None, "extfile_formset": None, "cleancomp_formset": None, "bulkassignprod_form": None, "product_formset": None, } # TODO: Lots of boilerplate code here. if dg.include_upload_docs_form(): if "uploaddocs-submit" in request.POST: form = UploadDocsForm(dg, request.POST, request.FILES) context["uploaddocs_form"] = UploadDocsForm( dg, request.POST, request.FILES) if form.is_valid(): num_saved = form.save() messages.success( request, "%d document%s uploaded successfully." % (num_saved, pluralize(num_saved)), ) else: errors = gather_errors(form) for e in errors: messages.error(request, e) else: context["uploaddocs_form"] = UploadDocsForm(dg) if dg.include_extract_form(): if "extfile-submit" in request.POST: formset = ExtractFileFormSet(dg, request.POST, request.FILES) context["extfile_formset"] = ExtractFileFormSet(dg, request.POST) if formset.is_valid(): num_saved = formset.save() messages.success( request, "%d extracted record%s uploaded successfully." % (num_saved, pluralize(num_saved)), ) else: errors = gather_errors(formset) for e in errors: messages.error(request, e) else: context["extfile_formset"] = ExtractFileFormSet(dg) if dg.include_clean_comp_data_form(): if "cleancomp-submit" in request.POST: formset = CleanCompFormSet(dg, request.POST, request.FILES) context["cleancomp_formset"] = CleanCompFormSet(dg, request.POST) if formset.is_valid(): num_saved = formset.save() messages.success( request, "%d clean composition data record%s uploaded successfully." % (num_saved, pluralize(num_saved)), ) else: errors = gather_errors(formset) for e in errors: messages.error(request, e) else: context["cleancomp_formset"] = CleanCompFormSet(dg) if dg.include_bulk_assign_form(): if "bulkassignprod-submit" in request.POST: form = BulkAssignProdForm(dg, request.POST, request.FILES) if form.is_valid(): num_saved = form.save() messages.success( request, "%d product%s created successfully." % (num_saved, pluralize(num_saved)), ) else: errors = gather_errors(form) for e in errors: messages.error(request, e) else: context["bulkassignprod_form"] = BulkAssignProdForm(dg) if dg.include_product_upload_form(): if "products-submit" in request.POST: product_formset = ProductBulkCSVFormSet(request.POST, request.FILES) if product_formset.is_valid(): num_saved, reports = product_formset.save() messages.success( request, f"{num_saved} records have been successfully uploaded.") messages.warning(request, reports) else: errors = gather_errors(product_formset) for e in errors: messages.error(request, e) else: context["product_formset"] = ProductBulkCSVFormSet() return render(request, template_name, context)
def audit_list_message(assignments_to_bonus, requester, is_worker, is_html, is_sandbox): total_unpaid = get_underpayment(assignments_to_bonus) signer = Signer(salt=get_salt()) message = "" if is_sandbox: message += "<p>" if is_html else "" message += "This message represents work that was done in the Amazon Mechanical Turk sandbox, not the live site." message += "</p>" if is_html else "\n\n" message += "<p>" if is_html else "" if is_worker: message += "This requester is " else: message += "You are " message += "using the <a href='%s'>Fair Work script</a> " % settings.HOSTNAME if is_html else "using the Fair Work script (%s) " % settings.HOSTNAME message += "to ensure pay rates reach a minimum wage of $%.2f/hr. " % ( settings.MINIMUM_WAGE_PER_HOUR) message += "Fair Work does this by asking for completion times and then auto-bonusing workers to meet the desired hourly wage of $%.2f/hr." % ( settings.MINIMUM_WAGE_PER_HOUR) message += "</p>" if is_html else "\n\n" if not is_worker: message += "<p>" if is_html else "" message += "Bonuses will be sent in %d hours: %s. You can review the pending bonuses below and freeze bonuses if something looks unusual. Please remember to trust the workers' estimates, and only freeze bonuses if absolutely needed." % ( REQUESTER_GRACE_PERIOD.total_seconds() / (60 * 60), timezone.localtime(timezone.now() + REQUESTER_GRACE_PERIOD ).strftime("%B %d at %-I:%M%p %Z")) message += "</p>" if is_html else "\n\n" message += "<p>" if is_html else "" message += "The total bonus amount is $%.2f. The tasks being bonused:" % total_unpaid message += "</p><ul>" if is_html else "\n\n" hit_types = HITType.objects.filter( hit__assignment__assignmentaudit__in=assignments_to_bonus).distinct() for hit_type in hit_types: hittype_assignments = assignments_to_bonus.filter( assignment__hit__hit_type=hit_type) hits = HIT.objects.filter( assignment__assignmentaudit__in=hittype_assignments).distinct() workers = Worker.objects.filter( assignment__assignmentaudit__in=hittype_assignments).distinct() s = "<li>" if is_html else "" underpayment = hittype_assignments[0].get_underpayment() time_nomicroseconds = str( hittype_assignments[0].estimated_time).split(".")[0] if underpayment is None: summary = "HIT Type {hittype:s} originally paid ${payment:.2f} per task. No workers reported time elapsed for this HIT, so effective rate cannot be estimated. No bonuses will be sent.".format( hittype=hit_type.id, payment=hit_type.payment) elif underpayment <= Decimal('0.00'): summary = "HIT Type {hittype:s} originally paid ${payment:.2f} per task. Median estimated time across {num_workers:d} worker{workers_plural:s} was {estimated:s}, for an estimated rate of ${paymentrate:.2f}/hr. No bonus necessary.".format( hittype=hit_type.id, payment=hit_type.payment, estimated=time_nomicroseconds, paymentrate=hittype_assignments[0].estimated_rate, num_workers=len(workers), workers_plural=pluralize(len(workers))) else: paymentrevised = hit_type.payment + hittype_assignments[ 0].get_underpayment() bonus = underpayment.quantize(Decimal('1.000')).normalize( ) if underpayment >= Decimal(0.01) else underpayment.quantize( Decimal('1.000')) paymentrevised = paymentrevised.quantize( Decimal('1.000')).normalize() if paymentrevised >= Decimal( 0.01) else paymentrevised.quantize(Decimal('1.000')) if is_worker: summary = "HIT Type {hittype:s} originally paid ${payment:.2f} per task. Median estimated time was {estimated:s}, for an estimated rate of ${paymentrate:.2f}/hr. Bonus ${bonus:f} for each assignment in HIT{hits_plural:s} to bring the payment to a suggested ${paymentrevised:f} each.".format( hittype=hit_type.id, payment=hit_type.payment, estimated=time_nomicroseconds, paymentrate=hittype_assignments[0].estimated_rate, bonus=bonus, hits_plural=pluralize(len(hits)), paymentrevised=paymentrevised) else: summary = "HIT Type {hittype:s} originally paid ${payment:.2f} per task. Median estimated time across {num_workers:d} worker{workers_plural:s} was {estimated:s}, for an estimated rate of ${paymentrate:.2f}/hr. Bonus ${bonus:f} for each of {num_assignments:d} assignment{assignment_plural:s} in {num_hits:d} HIT{hits_plural:s} to bring the payment to a suggested ${paymentrevised:f} each. Total: ${totalbonus:.2f} bonus.".format( hittype=hit_type.id, payment=hit_type.payment, estimated=time_nomicroseconds, paymentrate=hittype_assignments[0].estimated_rate, bonus=bonus, num_assignments=len(hittype_assignments), assignment_plural=pluralize(len(hittype_assignments)), num_hits=len(hits), hits_plural=pluralize(len(hits)), num_workers=len(workers), workers_plural=pluralize(len(workers)), paymentrevised=paymentrevised, totalbonus=get_underpayment(hittype_assignments)) s += summary s += "<ul>" if is_html else "\n" # anon_worker_id = 1 if not is_worker: for worker in workers: duration_query = AssignmentDuration.objects.filter( assignment__worker=worker ).filter(assignment__hit__hit_type=hit_type).filter( assignment__assignmentaudit__in=assignments_to_bonus) if len(duration_query) > 0: median_duration = median( duration_query.values_list('duration', flat=True)) median_nomicroseconds = str(median_duration).split(".")[0] s += "<li>" if is_html else "\t" # if is_worker: # s += "Worker " + str(anon_worker_id) + ": " # anon_worker_id += 1 # else: s += "Worker %s: " % worker.id s += "{num_reports:d} report{report_plural:s}, median duration {median_duration:s}. ".format( num_reports=len(duration_query), report_plural=pluralize(len(duration_query)), median_duration=median_nomicroseconds) if not is_worker: worker_signed = signer.sign(worker.id) freeze_url = settings.HOSTNAME + reverse( 'freeze', kwargs={ 'requester': requester.aws_account, 'worker_signed': worker_signed }) if is_html: s += "<a href='{freeze_url:s}'>Freeze this worker's payment</a>".format( freeze_url=freeze_url) else: s += "Freeze this worker's payment: {freeze_url:s}".format( freeze_url=freeze_url) s += "</li>" if is_html else "\n" # maybe else say something like this worker is probably frozen s += "</li>" if is_html else "\n\n" message += s return message
def process_import(self, request, *args, **kwargs): ''' Perform the actual import action (after the user has confirmed he wishes to import) ''' opts = self.model._meta resource = self.get_import_resource_class()() total_imports = 0 total_updates = 0 confirm_form = ConfirmImportForm(request.POST) if confirm_form.is_valid(): import_formats = self.get_import_formats() input_format = import_formats[int( confirm_form.cleaned_data['input_format'])]() tmp_storage = self.get_tmp_storage_class()( name=confirm_form.cleaned_data['import_file_name']) data = tmp_storage.read(input_format.get_read_mode()) if not input_format.is_binary() and self.from_encoding: data = force_text(data, self.from_encoding) dataset = input_format.create_dataset(data) result = resource.import_data( dataset, dry_run=False, raise_errors=True, file_name=confirm_form.cleaned_data['original_file_name'], user=request.user) if not self.get_skip_admin_log(): # Add imported objects to LogEntry logentry_map = { RowResult.IMPORT_TYPE_NEW: ADDITION, RowResult.IMPORT_TYPE_UPDATE: CHANGE, RowResult.IMPORT_TYPE_DELETE: DELETION, } content_type_id = ContentType.objects.get_for_model( self.model).pk for row in result: if row.import_type != row.IMPORT_TYPE_SKIP: LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=content_type_id, object_id=row.object_id, object_repr=row.object_repr, action_flag=logentry_map[row.import_type], change_message="%s through import_export" % row.import_type, ) if row.import_type == row.IMPORT_TYPE_NEW: total_imports += 1 elif row.import_type == row.IMPORT_TYPE_UPDATE: total_updates += 1 success_message = u'Import finished, with {} new {}{} and ' \ u'{} updated {}{}.'.format(total_imports, opts.model_name, pluralize(total_imports), total_updates, opts.model_name, pluralize(total_updates)) messages.success(request, success_message) tmp_storage.remove() url = reverse('admin:%s_%s_changelist' % self.get_model_info(), current_app=self.admin_site.name) return HttpResponseRedirect(url)
def get_detail(self): jrs = int(self.array_infos.get("ban-jrs")) return (_( u'vous ne pouvez plus vous connecter sur {0} pendant {1} jour{2}.' ).format(settings.ZDS_APP['site']['litteral_name'], jrs, pluralize(jrs)))
def location(request, location_code): user = request.user location = get_object_or_404(Location, code=location_code.upper()) complete = False if request.method == "POST": subscription_id = request.POST.get('subscription_id') try: subscription = user.subscriptions.active().get(pk=subscription_id) except Subscription.DoesNotExist as ex: # TODO: handle this raise ex box_plural = lambda n: pluralize(n, "box,boxes") with transaction.atomic(): if len(request.POST.get('number_of_boxes')) > 0 and int( request.POST.get('number_of_boxes')) > 0: number_of_boxes = int(request.POST.get('number_of_boxes', 1)) if subscription.can_tag_location(location, number_of_boxes): subscription.tag_location(location, number_of_boxes, user) if location.service == location.CHECKIN: msg = "You have returned {} {}.".format( number_of_boxes, box_plural(number_of_boxes)) else: msg = "You have checked out {} {}.".format( number_of_boxes, box_plural(number_of_boxes)) complete = True messages.success(request, msg) else: if location.service == location.CHECKIN: if number_of_boxes == 1: msg = "You have returned all of your boxes for this subscription." else: msg = ( "You do not have {} {} checked out with this " "subscription.").format( number_of_boxes, box_plural(number_of_boxes)) else: if number_of_boxes == 1: msg = ( "You do not have enough boxes to check out with " "this subscription.") else: msg = ( "You do not have enough boxes to check out {} {} " "with this subscription.").format( number_of_boxes, box_plural(number_of_boxes)) messages.error(request, msg) else: msg = ("Please enter a valid positive number") messages.error(request, msg) subscriptions = [{ "id": subscription.pk, "name": subscription.plan_display, "max_boxes": subscription.number_of_boxes, "available_boxes": subscription.available_boxes, } for subscription in user.subscriptions.active()] return render( request, "core/location.djhtml", { "location": location, "subscriptions": subscriptions, "boxesCheckedIn": user.total_boxes_checkedin(), "communityBoxesCheckedIn": int((LocationTag.objects.all()).count() / 2) + 100, "complete": complete, })
def test_pluralize(self): self.assertEqual(pluralize(1), '') self.assertEqual(pluralize(0), 's') self.assertEqual(pluralize(2), 's') self.assertEqual(pluralize([1]), '') self.assertEqual(pluralize([]), 's') self.assertEqual(pluralize([1, 2, 3]), 's') self.assertEqual(pluralize(1, 'es'), '') self.assertEqual(pluralize(0, 'es'), 'es') self.assertEqual(pluralize(2, 'es'), 'es') self.assertEqual(pluralize(1, 'y,ies'), 'y') self.assertEqual(pluralize(0, 'y,ies'), 'ies') self.assertEqual(pluralize(2, 'y,ies'), 'ies') self.assertEqual(pluralize(0, 'y,ies,error'), '')
def get_detail(self): jrs = int(self.array_infos.get("ls-jrs")) return (_( u'vous ne pouvez plus poster dans les forums, ni dans les ' u'commentaires d\'articles et de tutoriels pendant {0} jour{1}.'). format(jrs, pluralize(jrs)))
class Freelancer(PolymorphicModel): "A freelancer is a person offering a professional service." service = None # Needed for API published = models.BooleanField( default=False, help_text='Whether or not the freelancer is matched with jobs.') # A link to a user account. user = models.ForeignKey(settings.AUTH_USER_MODEL, unique=True) first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) mobile = models.CharField( max_length=13, validators=[mobile_validator], help_text='Your mobile phone number will be visible to clients on ' 'whose jobs you are booked.') photo = models.ImageField(upload_to='freelancer/photos/%Y/%m/%d', blank=True) FLUENCY_BASIC = 'BA' FLUENCY_CONVERSATIONAL = 'CO' FLUENCY_FLUENT = 'FL' FLUENCY_NATIVE = 'NA' FLUENCY_CHOICES = ( (FLUENCY_BASIC, 'Basic'), (FLUENCY_CONVERSATIONAL, 'Conversational'), (FLUENCY_FLUENT, 'Fluent'), (FLUENCY_NATIVE, 'Native'), ) english_fluency = models.CharField(max_length=2, choices=FLUENCY_CHOICES) eligible_to_work = models.BooleanField('I am eligible to work in the UK.', default=False) # TODO - Legacy field, remove once migrated PHONE_TYPE_ANDROID = 'AN' PHONE_TYPE_IPHONE = 'IP' PHONE_TYPE_WINDOWS = 'WI' PHONE_TYPE_OTHER = 'OT' PHONE_TYPE_NON_SMARTPHONE = 'NS' PHONE_TYPE_CHOICES = ( (PHONE_TYPE_ANDROID, 'Android'), (PHONE_TYPE_IPHONE, 'iPhone'), (PHONE_TYPE_WINDOWS, 'Windows'), (PHONE_TYPE_OTHER, 'Other smartphone'), (PHONE_TYPE_NON_SMARTPHONE, 'Non smartphone'), ) phone_type_old = models.CharField(max_length=2, choices=PHONE_TYPE_CHOICES, blank=True) # TODO - remove days_available and hours_available DAYS_OF_WEEK_CHOICES = [ (calendar.day_abbr[i].lower(), calendar.day_name[i]) for i in range(7) ] days_available = MultiSelectField( 'Which days of the week are you available to work?', choices=DAYS_OF_WEEK_CHOICES, blank=True) HOURS_AVAILABLE_MORNINGS = 'MO' HOURS_AVAILABLE_AFTERNOONS = 'AF' HOURS_AVAILABLE_EVENINGS = 'EV' HOURS_AVAILABLE_NIGHT = 'NI' HOURS_AVAILABLE_CHOICES = ( (HOURS_AVAILABLE_MORNINGS, 'Mornings'), (HOURS_AVAILABLE_AFTERNOONS, 'Afternoons'), (HOURS_AVAILABLE_EVENINGS, 'Evenings'), (HOURS_AVAILABLE_NIGHT, 'Night'), ) # Mornings, Afternoons, Evenings, Night, Flexible hours_available = MultiSelectField( 'What are your preferred working hours?', choices=HOURS_AVAILABLE_CHOICES, blank=True) minimum_pay_per_hour = MoneyField( max_digits=5, decimal_places=2, default_currency='GBP', default=Decimal(FREELANCER_MIN_WAGE), help_text='The minimum pay per hour you will accept.', validators=[validators.MinValueValidator(FREELANCER_MIN_WAGE)]) postcode = models.ForeignKey(Postcode, blank=True, null=True) DISTANCE_CHOICES = [(i, "%s mile%s" % (str(apnumber(i)).capitalize(), pluralize(i))) \ for i in (1, 2, 5, 10, 20, 50)] travel_distance = models.PositiveSmallIntegerField( choices=DISTANCE_CHOICES, default=5, help_text='The maximum distance you are prepared to travel to a job.') # The integer stored in experience denotes that they have # AT LEAST that number of years experience. YEARS_EXPERIENCE_LESS_ONE = 0 YEARS_EXPERIENCE_ONE = 1 YEARS_EXPERIENCE_THREE = 3 YEARS_EXPERIENCE_FIVE = 5 YEARS_EXPERIENCE_CHOICES = ( (YEARS_EXPERIENCE_LESS_ONE, 'Less than 1 year'), (YEARS_EXPERIENCE_ONE, '1 - 3 years'), (YEARS_EXPERIENCE_THREE, '3 - 5 years'), (YEARS_EXPERIENCE_FIVE, 'More than 5 years'), ) years_experience = models.PositiveSmallIntegerField( default=YEARS_EXPERIENCE_ONE, choices=YEARS_EXPERIENCE_CHOICES) objects = GeoPolymorphicManager() published_objects = PublishedFreelancerManager() # stores information on the last application_date last_applied = models.DateField(auto_now_add=True) def save(self, *args, **kwargs): if self.published == True: self.last_applied = date.today() super(Freelancer, self).save(*args, **kwargs) @property def reference_number(self): "Returns a reference number for this freelancer." return 'FR%s' % str(self.pk).zfill(7) @property def is_active(self): delta = date.today() - self.last_applied return (self.published and (delta.days <= 14)) def get_full_name(self): "Returns the full name of the freelancer." return '%s %s' % (self.first_name, self.last_name) def get_absolute_url(self): return reverse('freelancer_detail', args=(self.pk, )) def __unicode__(self): return self.get_full_name() class Meta: ordering = 'last_name',
def message(count, noun, verb): return ('{} ' + noun + '{} {} ' + verb).format(count, pluralize(count), pluralize(count, 'was,were'))
def __str__(self): return "Track({} | {} point{})".format( self.name if self.name else self.id, self.point_count(), pluralize(self.point_count()))
def __str__(self): return 'Segment({} | {} point{})'.format(self.id, self.point_count(), pluralize(self.point_count()))
def syncdata(self, fixture_labels, options): verbosity = options['verbosity'] show_traceback = options['traceback'] # Keep a count of the installed objects and fixtures fixture_count = 0 object_count = 0 objects_per_fixture = [] models = set() # Get a cursor (even though we don't need one yet). This has # the side effect of initializing the test database (if # it isn't already initialized). cursor = connections[self.using].cursor() app_modules = [app.module for app in apps.get_app_configs()] app_fixtures = [ os.path.join(os.path.dirname(app.__file__), 'fixtures') for app in app_modules ] for fixture_label in fixture_labels: parts = fixture_label.split('.') if len(parts) == 1: fixture_name = fixture_label formats = serializers.get_public_serializer_formats() else: fixture_name, format_ = '.'.join(parts[:-1]), parts[-1] if format_ in serializers.get_public_serializer_formats(): formats = [format_] else: formats = [] if formats: if verbosity > 1: print("Loading '%s' fixtures..." % fixture_name) else: raise SyncDataError( "Problem installing fixture '%s': %s is not a known serialization format." % (fixture_name, format_)) if os.path.isabs(fixture_name): fixture_dirs = [fixture_name] else: fixture_dirs = app_fixtures + list( settings.FIXTURE_DIRS) + [''] for fixture_dir in fixture_dirs: if verbosity > 1: print("Checking %s for fixtures..." % humanize(fixture_dir)) label_found = False for format_ in formats: if verbosity > 1: print("Trying %s for %s fixture '%s'..." % (humanize(fixture_dir), format_, fixture_name)) try: full_path = os.path.join( fixture_dir, '.'.join([fixture_name, format_])) fixture = open(full_path, 'r') if label_found: fixture.close() raise SyncDataError( "Multiple fixtures named '%s' in %s. Aborting." % (fixture_name, humanize(fixture_dir))) else: fixture_count += 1 objects_per_fixture.append(0) if verbosity > 0: print("Installing %s fixture '%s' from %s." % (format_, fixture_name, humanize(fixture_dir))) try: objects_to_keep = {} objects = list( serializers.deserialize(format_, fixture)) for obj in objects: class_ = obj.object.__class__ if class_ not in objects_to_keep: objects_to_keep[class_] = set() objects_to_keep[class_].add(obj.object) if options['remove'] and options[ 'remove_before']: self.remove_objects_not_in( objects_to_keep, verbosity) for obj in objects: object_count += 1 objects_per_fixture[-1] += 1 models.add(obj.object.__class__) obj.save() if options['remove'] and not options[ 'remove_before']: self.remove_objects_not_in( objects_to_keep, verbosity) label_found = True except (SystemExit, KeyboardInterrupt): raise except Exception: import traceback fixture.close() if show_traceback: traceback.print_exc() raise SyncDataError( "Problem installing fixture '%s': %s\n" % (full_path, traceback.format_exc())) fixture.close() except SyncDataError as e: raise e except Exception: if verbosity > 1: print( "No %s fixture '%s' in %s." % (format_, fixture_name, humanize(fixture_dir))) # If any of the fixtures we loaded contain 0 objects, assume that an # error was encountered during fixture loading. if 0 in objects_per_fixture: raise SyncDataError( "No fixture data found for '%s'. (File format may be invalid.)" % fixture_name) # If we found even one object in a fixture, we need to reset the # database sequences. if object_count > 0: sequence_sql = connections[self.using].ops.sequence_reset_sql( self.style, models) if sequence_sql: if verbosity > 1: print("Resetting sequences") for line in sequence_sql: cursor.execute(line) if object_count == 0: if verbosity > 1: print("No fixtures found.") else: if verbosity > 0: print("Installed %d object%s from %d fixture%s" % (object_count, pluralize(object_count), fixture_count, pluralize(fixture_count)))
def __str__(self): return "Invalid schema%s: %s" % (pluralize(self.schema), ','.join(self.schema))
def test_value_error(self): self.assertEqual(pluralize('', 'y,es'), '') self.assertEqual(pluralize('', 'es'), '')
def test_pluralize(self): self.assertEqual(pluralize(1), '') self.assertEqual(pluralize(0), 's') self.assertEqual(pluralize(2), 's') # Ticket #22798 self.assertEqual(pluralize(0.5), 's') self.assertEqual(pluralize(1.5), 's') self.assertEqual(pluralize(decimal.Decimal(1)), '') self.assertEqual(pluralize(decimal.Decimal(0)), 's') self.assertEqual(pluralize(decimal.Decimal(2)), 's') self.assertEqual(pluralize([1]), '') self.assertEqual(pluralize([]), 's') self.assertEqual(pluralize([1, 2, 3]), 's') self.assertEqual(pluralize(1, 'es'), '') self.assertEqual(pluralize(0, 'es'), 'es') self.assertEqual(pluralize(2, 'es'), 'es') self.assertEqual(pluralize(1, 'y,ies'), 'y') self.assertEqual(pluralize(0, 'y,ies'), 'ies') self.assertEqual(pluralize(2, 'y,ies'), 'ies') self.assertEqual(pluralize(0, 'y,ies,error'), '')
def display_name(self): make = self.make if self.make != "" else "Unknown Make" model = self.model if self.model != "" else "Unknown Model" count = "(%s outlet%s)" % (self.max_outlets, pluralize(self.max_outlets)) if self.max_outlets > 0 else "" return ("%s %s %s" % (make, model, count)).strip()
def body(self): hours = interval_to_hours(self.a.actual_time) return "{:.2f} hour{}".format(hours, pluralize(hours))
def test_no_len_type(self): self.assertEqual(pluralize(object(), 'y,es'), '') self.assertEqual(pluralize(object(), 'es'), '')
def up_count(story): count = story.up_count if hasattr(story, 'up_count') else story['up_count'] if count: return '{:d} new chapter{}'.format(count, pluralize(count)) else: return 'revised'
def test_lists(self): self.assertEqual(pluralize([1]), '') self.assertEqual(pluralize([]), 's') self.assertEqual(pluralize([1, 2, 3]), 's')
def seconds_to_time_string(seconds_init, short_display = True): seconds = seconds_init years = math.floor(seconds / (86400 * 365)) seconds -= years * (86400 * 365) days = math.floor(seconds / 86400) seconds -= days * 86400 hours = math.floor(seconds / 3600) seconds -= hours * 3600 minutes = math.floor(seconds / 60) seconds -= minutes * 60 if years and days: return "%d year%s and %d day%s" % (years, pluralize(years), days, pluralize(days)) elif years: return "%d year%s" % (years, pluralize(years)) elif days and hours: return "%d day%s and %d hour%s" % (days, pluralize(days), hours, pluralize(hours)) elif days: return "%d day%s" % (days, pluralize(days)) elif hours: if not short_display and minutes: return "%d hour%s and %d minute%s" % (hours, pluralize(hours), minutes, pluralize(minutes)) else: return "%d hour%s" % (hours, pluralize(hours)) else: if not short_display and seconds and not minutes: return "%d second%s" % (seconds, pluralize(seconds)) return "%d minute%s" % (minutes, pluralize(minutes))
def test_decimals(self): self.assertEqual(pluralize(Decimal(1)), '') self.assertEqual(pluralize(Decimal(0)), 's') self.assertEqual(pluralize(Decimal(2)), 's')
def field_value(revision, field): value = getattr(revision, field) if field in [ 'is_surrogate', 'no_volume', 'display_volume_with_number', 'no_brand', 'page_count_uncertain', 'title_inferred', 'no_barcode', 'no_indicia_frequency', 'no_isbn', 'year_began_uncertain', 'year_ended_uncertain', 'on_sale_date_uncertain', 'is_comics_publication' ]: return yesno(value, 'Yes,No') elif field in ['is_current']: res_holder_display = '' if revision.previous(): reservation = revision.source.get_ongoing_reservation() if revision.previous().is_current and not value and reservation: res_holder = reservation.indexer res_holder_display = ' (ongoing reservation held by %s %s)' % \ (res_holder.first_name, res_holder.last_name) return yesno(value, 'Yes,No') + res_holder_display elif field in [ 'publisher', 'indicia_publisher', 'series', 'origin_issue', 'target_issue' ]: return absolute_url(value) elif field in ['origin', 'target']: return value.full_name_with_link() elif field == 'brand': if value and value.emblem: if settings.FAKE_IMAGES: return absolute_url(value) else: return mark_safe('<img src="' + value.emblem.icon.url + '"> ' \ + absolute_url(value)) return absolute_url(value) elif field in [ 'notes', 'tracking_notes', 'publication_notes', 'characters', 'synopsis' ]: return linebreaksbr(value) elif field == 'reprint_notes': reprint = '' if value.strip() != '': for string in split_reprint_string(value): string = string.strip() reprint += '<li> ' + esc(string) + ' </li>' if reprint != '': reprint = '<ul>' + reprint + '</ul>' return mark_safe(reprint) elif field in ['url']: return urlize(value) elif field in ['indicia_pub_not_printed']: return yesno(value, 'Not Printed,Printed') elif field == 'group': brand_groups = '' for brand in value.all(): brand_groups += absolute_url(brand) + '; ' if brand_groups: brand_groups = brand_groups[:-2] return mark_safe(brand_groups) elif field in [ 'no_editing', 'no_script', 'no_pencils', 'no_inks', 'no_colors', 'no_letters' ]: return yesno(value, 'X, ') elif field in ['page_count']: if revision.source_name == 'issue' and \ revision.changeset.storyrevisions.count(): # only calculate total sum for issue not sequences total_pages = sum_page_counts(revision.active_stories()) if revision.variant_of: if revision.changeset.issuerevisions.count() > 1: stories = revision.changeset.storyrevisions\ .exclude(issue=revision.issue) else: stories = revision.variant_of.active_stories() if revision.active_stories().count(): # variant has cover sequence, add page counts without cover stories = stories.exclude(sequence_number=0) total_pages += sum_page_counts(stories) else: # variant has no extra cover sequence total_pages = sum_page_counts(stories) sum_story_pages = format_page_count(total_pages) return u'%s (note: total sum of story page counts is %s)' % \ (format_page_count(value), sum_story_pages) return format_page_count(value) elif field == 'isbn': if value: if validated_isbn(value): return u'%s (note: valid ISBN)' % show_isbn(value) elif len(value.split(';')) > 1: return_val = show_isbn(value) + ' (note: ' for isbn in value.split(';'): return_val = return_val + u'%s; ' % ("valid ISBN" \ if validated_isbn(isbn) else "invalid ISBN") return return_val + 'ISBNs are inequal)' elif value: return u'%s (note: invalid ISBN)' % value elif field == 'barcode': if value: barcodes = value.split(';') return_val = show_barcode(value) + ' (note: ' for barcode in barcodes: return_val = return_val + u'%s; ' % ("valid UPC/EAN part" \ if valid_barcode(barcode) \ else "invalid UPC/EAN part or non-standard") return return_val[:-2] + ')' elif field == 'leading_article': if value == True: return u'Yes (sorted as: %s)' % remove_leading_article( revision.name) else: return u'No' elif field in [ 'has_barcode', 'has_isbn', 'has_issue_title', 'has_indicia_frequency', 'has_volume', 'has_rating' ]: if hasattr(revision, 'changed'): if revision.changed[field] and value == False: kwargs = {field[4:]: ''} if field[4:] == 'issue_title': kwargs = {'title': ''} if revision.series: value_count = revision.series.active_issues()\ .exclude(**kwargs).count() if value_count: return 'No (note: %d issues have a non-empty %s value)' % \ (value_count, field[4:]) return yesno(value, 'Yes,No') elif field == 'is_singleton': if hasattr(revision, 'changed'): if revision.changed[field] and value == True: if revision.series: value_count = revision.series.active_base_issues().count() if value_count != 1: return 'Yes (note: the series has %d issue%s)' % \ (value_count, pluralize(value_count)) elif revision.series.active_issues()\ .exclude(indicia_frequency='').count(): return 'Yes (note: the issue has an indicia frequency)' return yesno(value, 'Yes,No') elif field == 'after' and not hasattr(revision, 'changed'): # for previous revision (no attr changed) display empty string return '' elif field == 'cr_creator_names': creator_names = ", ".join(revision.cr_creator_names.all().values_list( 'name', flat=True)) return creator_names return value
def test_floats(self): self.assertEqual(pluralize(0.5), 's') self.assertEqual(pluralize(1.5), 's')
def get_type(self): jrs = int(self.array_infos.get("ban-jrs")) return _("Bannissement temporaire ({0} jour{1})").format( jrs, pluralize(jrs))
def test_integers(self): self.assertEqual(pluralize(1), '') self.assertEqual(pluralize(0), 's') self.assertEqual(pluralize(2), 's')
def post(self, *args, **kwargs): proposal_pks = self.request.POST.getlist("proposal_pk") proposals = Proposal.objects.filter(pk__in=proposal_pks) new_status = self.request.POST.get("mark_status") if new_status: # <queryset>.update() will not work here because # the status field lives in the related model # ProposalResult. for proposal in proposals: try: proposal.review_result.status = new_status proposal.review_result.save() except ProposalResult.DoesNotExist: proposal.review_result = ProposalResult.objects.create( proposal=proposal, status=new_status) return HttpResponseRedirect( reverse("review_proposal_result_list", args=[new_status])) elif self.request.POST.get("send_notification"): # Save ProposalNotification to database, as a type # of rudimentary logging. notification = ProposalNotification.objects.create( from_address=self.request.POST.get("from_address"), subject=self.request.POST.get("subject"), body=self.request.POST.get("body"), ) notification.proposals.set(proposals) unemailed_speakers = notification.send_email() for speaker in unemailed_speakers: messages.warning( self.request, "Speaker {} does not have an email address " "and has not been notified.".format(speaker.name)) return HttpResponseRedirect(reverse("review_proposal_list")) elif self.request.POST.get("create_presentations"): num_presentations_created = 0 for proposal in proposals: # We don't need to add all of the proposal's metadata # to the presentation. Most fields will automatically be # added when we save the proposal. # See https://github.com/pydata/conf_site/pull/176. # Note that the title needs to be added here so that # a presentation's slugs are created properly. presentation, created = Presentation.objects.get_or_create( proposal_base=proposal.proposalbase_ptr, section=proposal.section, speaker=proposal.speaker, title=proposal.title, ) # If the presentation already existed, we do not need # to attach it to the proposal. if created: proposal.presentation = presentation proposal.save() num_presentations_created += 1 # Create a message if any new presentations were created. if num_presentations_created: messages.success( self.request, "{} presentation{} created.".format( num_presentations_created, pluralize(num_presentations_created), ), ) else: messages.warning( self.request, "All selected proposals already had presentations.", ) # Since the "create presentations" action can only # be initated from the "Accepted Proposals" # category listing, we return the user there. return HttpResponseRedirect( reverse( "review_proposal_result_list", args=[ProposalResult.RESULT_ACCEPTED], ))
def get_exercise_focus_data(user, user_data, daily_activity_logs, dt_start_utc, dt_end_utc): total_seconds = 0 dict_exercise_seconds = {} for daily_activity_log in daily_activity_logs: activity_summary = daily_activity_log.activity_summary for hour in activity_summary.hourly_summaries: hourly_activity_summary = activity_summary.hourly_summaries[hour] # We need to filter for dates outside of our range here because we expanded our DB query # to make sure we got the entire client time zone date range if hourly_activity_summary.date < dt_start_utc or hourly_activity_summary.date > dt_end_utc: continue for exercise_key in hourly_activity_summary.dict_exercises.keys(): hourly_activity_summary_exercise_item = hourly_activity_summary.dict_exercises[ exercise_key] exid = hourly_activity_summary_exercise_item.exercise key_exercise = exid.lower() if not dict_exercise_seconds.has_key(key_exercise): dict_exercise_seconds[key_exercise] = { "exercise_title": models.Exercise.to_display_name(exid), "exid": exid, "seconds": 0, "correct": 0, "problems": 0 } dict_exercise_seconds[key_exercise][ "seconds"] += hourly_activity_summary_exercise_item.time_taken dict_exercise_seconds[key_exercise][ "problems"] += hourly_activity_summary_exercise_item.c_problems dict_exercise_seconds[key_exercise][ "correct"] += hourly_activity_summary_exercise_item.c_correct total_seconds += hourly_activity_summary_exercise_item.time_taken keys = dict_exercise_seconds.keys() for key_exercise in keys: percentage = int( float(dict_exercise_seconds[key_exercise]["seconds"]) / float(total_seconds) * 100.0) if percentage: dict_exercise_seconds[key_exercise]["percentage"] = percentage dict_exercise_seconds[key_exercise][ "time_spent"] = util.seconds_to_time_string( dict_exercise_seconds[key_exercise]["seconds"], False) correct = dict_exercise_seconds[key_exercise]["correct"] dict_exercise_seconds[key_exercise][ "s_correct_problems"] = "%d correct problem%s without a hint" % ( correct, pluralize(correct)) problems = dict_exercise_seconds[key_exercise]["problems"] dict_exercise_seconds[key_exercise][ "s_problems"] = "%d total problem%s" % (problems, pluralize(problems)) dict_exercise_seconds[key_exercise][ "proficient"] = user_data.is_proficient_at(key_exercise, user) else: # Don't bother showing 0 percentage exercises del dict_exercise_seconds[key_exercise] return (total_seconds, dict_exercise_seconds)