Utilities

In the following sections, the most important functions, classes, and exception classes are mentioned and explained. This covers everything that is used in the “institute” app. It should give you a solid starting point for creating an own institute app. Nevertheless, the utility modules contain even more functions and classes.

Common helpers

Generating responses

The following names are found in the module jb_common.utils.base.

exception JSONRequestException(error_number, error_message)

Exception which is raised if a JSON response was requested and an error in the submitted data occured. This will result in an HTTP 422 response with a JSON-encoded (error code, error message) body. For example, in a JSON-only view function, you might say:

if not request.user.is_superuser:
    raise JSONRequestException(6, "Only admins can access this ressource.")

The ranges for the error codes are:

0–999
special codes, codes common to all applications, and JuliaBase-common
1000–1999
JuliaBase-samples
2000–2999
institute-specific extensions to JuliaBase-samples
3000–3999
JuliaBase-kicker

The complete table with the error codes is in the main __init__.py of the respective app.

is_json_requested(request)

Tests whether the current request should be answered in JSON format instead of HTML. Typically this means that the request was made by the JuliaBase Remote Client or by JavaScript code.

Parameters:request (HttpRequest) – the current HTTP Request object
Returns:whether the request should be answered in JSON
Return type:bool
respond_in_json(value)

The communication with the JuliaBase Remote Client or to AJAX clients should be done without generating HTML pages in order to have better performance. Thus, all responses are Python objects, serialised in JSON notation.

The views that can be accessed by the Remote Client/AJAX as well as normal browsers should distinguish between both by using is_json_requested.

Parameters:value (object (an arbitrary Python object)) – the data to be sent back to the client that requested JSON.
Returns:the HTTP response object
Return type:HttpResponse
static_file_response(filepath, served_filename=None)

Serves a file of the local file system.

Parameters:
  • filepath – the absolute path to the file to be served
  • served_filename – the filename the should be transmitted; if given, the response will be an “attachment”
Returns:

the HTTP response with the static file

Rype:

django.http.HttpResponse

The following name is found in the module samples.utils.views.

successful_response(request, success_report=None, view=None, kwargs={}, query_string='', forced=False, json_response=True)

After a POST request was successfully processed, there is typically a redirect to another page – maybe the main menu, or the page from where the add/edit request was started.

The latter is appended to the URL as a query string with the next key, e.g.:

/juliabase/5-chamber_deposition/08S-410/edit/?next=/juliabase/samples/08S-410a

This routine generated the proper HttpResponse object that contains the redirection. It always has HTTP status code 303 (“see other”).

If the request came from the JuliaBase Remote Client, the response is a pickled json_response. (Normally, a simple True.)

Parameters:
  • request (HttpRequest) – the current HTTP request
  • success_report (str) – an optional short success message reported to the user on the next view
  • view (str) – the view name to redirect to; defaults to the main menu page (same when None is given)
  • kwargs (dict) – group parameters in the URL pattern that have to be filled
  • query_string (str) – the quoted query string to be appended, without the leading "?"
  • forced (bool) – If True, go to view even if a “next” URL is available. Defaults to False. See bulk_rename.bulk_rename for using this option to generate some sort of nested forwarding.
  • json_response (object) – object which is to be sent as a pickled response to the remote client; defaults to True.
Returns:

the HTTP response object to be returned to the view’s caller

Return type:

HttpResponse

Miscellaneous

The following names are found in the module samples.utils.views.

convert_id_to_int(process_id)

If the user gives a process ID via the browser, it must be converted to an integer because this is what’s stored in the database. (Well, actually SQL gives a string, too, but that’s beside the point.) This routine converts it to a real integer and tests also for validity (not for availability in the database).

Parameters:process_id (str) – the pristine process ID as given via the URL by the user
Returns:the process ID as an integer number
Return type:int
Raises:Http404 – if the process_id didn’t represent an integer number.
table_export(request, data, label_column_heading)

Helper function which does almost all work needed for a CSV table export view. This is not a view per se, however, it is called by views, which have to do almost nothing anymore by themselves. See for example sample.export.

This function return the data in JSON format if this is requested by the Accept header field in the HTTP request.

Parameters:
  • request (HttpRequest) – the current HTTP Request object
  • data (samples.data_tree.DataNode) – the root node of the data tree
  • label_column_heading (str) – Description of the very first column with the table row headings, see generate_table_rows.
Returns:

the HTTP response object or a tuple with all needed forms to create the export view

Return type:

HttpResponse or tuple of django.forms.Form

The following names are found in the module jb_common.utils.base.

get_really_full_name(user)

Unfortunately, Django’s get_full_name method for users returns the empty string if the user has no first and surname set. However, it’d be sensible to use the login name as a fallback then. This is realised here.

Parameters:user (django.contrib.auth.models.User) – the user instance
Returns:The full, human-friendly name of the user
Return type:str
check_markdown(text)

Checks whether the Markdown input by the user contains only permitted syntax elements. I forbid images and headings so far.

Parameters:text – the Markdown input to be checked
Raises:ValidationError – if the text contained forbidden syntax elements.

Function decorator for views functions to set a help link for the view. The help link is embedded into the top line in the layout, see the template base.html. The default template jb_base.html prepends "http://www.juliabase.org/". But you may change that by overriding the help_link block in your own jb_base.html.

Parameters:link (str) – the relative URL to the help page.
send_email(subject, content, recipients, format_dict=None)

Sends one email to a user. Both subject and content are translated to the recipient’s language. To make this work, you must tag the original text with a dummy _ function in the calling content, e.g.:

_ = lambda x: x
send_mail(_("Error notification"), _("An error has occured."), user)
_ = ugettext

If you need to use string formatting à la

"Hello {name}".format(name=user.name)

you must pass a dictionary like {"name": user.name} to this function. Otherwise, translating wouldn’t work.

Parameters:
  • subject (str) – the subject of the email
  • content (str) – the content of the email; it may contain substitution tags
  • recipients – the recipients of the email
  • format_dict (dict mapping str to str) – the substitions used for the format string method for both the subject and the content
round(value, digits)

Method for rounding a numeric value to a fixed number of significant digits.

Parameters:
  • value (float) – the numeric value
  • digit – number of significant digits
Returns:

rounded value

Return type:

str

generate_permissions(permissions, class_name)

Auto-generates model permissions. It may be used in physical process classes – but not only there – like this:

class Meta(samples.models.PhysicalProcess.Meta):
    permissions = generate_permissions(
        {"add", "change", "view_every", "edit_permissions"}, "ModelClassName")
Parameters:
  • permissions (set of str) – The permissions to generate. Possible values are "add", "change", "view_every", and "edit_permissions".
  • class_name (str) – python class name of the model class, e.g. "LayerThicknessMeasurement".
Returns:

the permissions tuple

Return type:

tuple of (str, str)

Feed reporting

The following name is found in the module samples.utils.views.

class Reporter(originator)

This class contains all feed-generating routines as methods. Their names start with report_.... The main reason for putting them into a class is that this class assures that no user gets two feed entries. Therefore, if you want to report a certain database change to the users, create an instance of Reporter and call all methods that are related to the database change. Call the most meaningful method first, and the most general last. For example, when changing the data of a sample, the respective view calls the following methods in this order:

report_new_responsible_person_samples
report_changed_sample_topic
report_edited_samples

Of course, the first two are only called if the respective data change really happend. Thus, the new responsible person is signalled first, then all people about a possible topic change, and if this didn’t happen, all so-far un-signalled users get a general message about changed sample data.

If you want to signal something to all possibly interested users, no matter on which feed entries they already have received, just create a new instance of Reporter.

Mostly, you can call the method directly without binding the instance of Reporter to a name, as in:

feed_utils.Reporter(request.user).report_result_process(
        result, edit_description=None)
Variables:
  • interested_users – all users that get informed with the next generated feed entry by a call to __connect_with_users
  • already_informed_users – All users who have already received a feed entry from this instance of Reporter. They won’t get a second entry.
  • originator – the user responsible for the databse change reported by the feed entry of this instance of Reporter.

Class constructor.

Parameters:originator (django.contrib.auth.models.User) – the user who did the database change to be reported; almost always, this is the currently logged-in user
report_changed_sample_series_topic(sample_series, old_topic, edit_description)

Generate a feed entry about a topic change for a sample series. All members of the former topic and the new topic are informed. Note that it is possible that further things were changed in the sample series at the same time (reponsible person, samples …). They should be mentioned in the description by the one who changed it.

Parameters:
  • sample_series (list of samples.models.SampleSeries) – the sample series that went into a new topic
  • old_topic (jb_common.models.Topic) – the old topic of the samples; may be None if they weren’t in any topic before
  • edit_description (dict mapping str to object) – The dictionary containing data about what was edited in the sample series (besides the change of the topic). Its keys correspond to the fields of EditDescriptionForm.
report_changed_sample_topic(samples, old_topic, edit_description)

Generate a feed entry about a topic change for sample(s). All members of the former topic (if any) and the new topic are informed. Note that it is possible that further things were changed in the sample(s) at the same time (reponsible person, purpose …). They should be mentioned in the description by the one who changed it.

Parameters:
  • samples (list of samples.models.Sample) – the samples that went into a new topic
  • old_topic (jb_common.models.Topic) – the old topic of the samples; may be None if they weren’t in any topic before
  • edit_description (dict mapping str to object) – The dictionary containing data about what was edited in the samples (besides the change of the topic). Its keys correspond to the fields of EditDescriptionForm.
report_changed_topic_membership(users, topic, action)

Generate one feed entry for changed topic memberships, i.e. added or removed users in a topic.

Parameters:
  • users (iterable of django.contrib.auth.models.User) – the affected users
  • topic (jb_common.models.Topic) – the topic whose memberships have changed
  • action (str) – what was done; "added" for added users, "removed" for removed users
report_copied_my_samples(samples, recipient, comments)

Generate a feed entry for sample that one user has copied to another user’s “My Samples” list.

Parameters:
  • samples (list of samples.models.Sample) – the samples that were copied to another user
  • recipient (django.contrib.auth.models.User) – the other user who got the samples
  • comments (str) – a message from the sender to the recipient
report_deleted_process(process)

Generate a feed entry about a deletion of a process.

Parameters:process (samples.models.Process) – the process that was deleted
report_deleted_sample(sample)

Generate a feed entry about a deletion of a sample. All users who are allowed to see the sample and who have the sample on their “My Samples” list are informed.

Parameters:sample (samples.models.Sample) – the sample that was deleted
report_edited_sample_series(sample_series, edit_description)

Generate a feed entry about an edited of sample series. All users who have watches samples in this series are informed, including the currently responsible person (in case that it is not the originator).

Parameters:
  • sample_series (list of samples.models.SampleSeries) – the sample series that was edited
  • edit_description (dict mapping str to object) – The dictionary containing data about what was edited in the sample series. Its keys correspond to the fields of EditDescriptionForm.
report_edited_samples(samples, edit_description)

Generate a feed entry about a general edit of sample(s). All users who are allowed to see the sample and who have the sample on their “My Samples” list are informed.

Parameters:
  • samples (list of samples.models.Sample) – the samples that were edited
  • edit_description (dict mapping str to object) – The dictionary containing data about what was edited in the samples. Its keys correspond to the fields of EditDescriptionForm.
report_new_responsible_person_sample_series(sample_series, edit_description)

Generate a feed entry for a sample series that changed their currently responsible person. This feed entry is only sent to that new responsible person. Note that it is possible that further things were changed in the sample series at the same time (topic, samples …). They should be mentioned in the description by the formerly responsible person.

Parameters:
  • sample_series (list of samples.models.SampleSeries) – the sample series that got a new responsible person
  • edit_description (dict mapping str to object) – Dictionary containing data about what was edited in the sample series (besides the change of the responsible person). Its keys correspond to the fields of EditDescriptionForm.
report_new_responsible_person_samples(samples, edit_description)

Generate a feed entry for samples that changed their currently responsible person. This feed entry is only sent to that new responsible person. Note that it is possible that further things were changed in the sample(s) at the same time (topic, purpose …). They should be mentioned in the description by the formerly responsible person.

Parameters:
  • samples (list of samples.models.Sample) – the samples that got a new responsible person
  • edit_description (dict mapping str to object) – Dictionary containing data about what was edited in the samples (besides the change of the responsible person). Its keys correspond to the fields of EditDescriptionForm.
report_new_sample_series(sample_series)

Generate one feed entry for a new sample series.

Parameters:sample_series (samples.models.SampleSeries) – the sample series that was added
report_new_samples(samples)

Generate one feed entry for new samples. If more than one sample is in the given list, they are assumed to have been generated at the same time, so they should share the same topic and purpose.

If the sample or samples are not in a topic, no feed entry is generated (because nobody listens).

Parameters:samples (list of samples.models.Sample) – the samples that were added
report_physical_process(process, edit_description=None)

Generate a feed entry for a physical process (deposition, measurement, etching etc) which was recently edited or created. If the process is still unfinished, nothing is done.

Parameters:
  • process (samples.models.Process) – the process which was added/edited recently
  • edit_description (dict mapping str to object) – The dictionary containing data about what was edited in the process. Its keys correspond to the fields of EditDescriptionForm. None if the process was newly created.
report_removed_task(task)

Generate one feed for a removed task. It is called immediately before the task is actually deleted.

Parameters:task (models.Task) – the to-be-deleted task
report_result_process(result, edit_description=None)

Generate a feed entry for a result process which was recently edited or created.

Parameters:
  • result (samples.models.Result) – the result process which was added/edited recently
  • edit_description (dict mapping str to object) – The dictionary containing data about what was edited in the result. Its keys correspond to the fields of EditDescriptionForm. None if the process was newly created.
report_sample_split(sample_split, sample_completely_split)

Generate a feed entry for a sample split.

Parameters:
  • sample_split (samples.models.SampleSplit) – sample split that is to be reported
  • sample_completely_split (bool) – whether the sample was completely split, i.e. no piece of the parent sample is left
report_status_message(process_class, status_message)

Generate one feed entry for new status messages for physical processes.

Parameters:
  • process_class (django.contrib.contenttypes.models.ContentType) – the content type of the physical process whose status has changed
  • status_message (samples.models.StatusMessage) – the status message for the physical process
report_task(task, edit_description=None)

Generate one feed entry for a new task or an edited task.

Parameters:
  • task (models.Task) – the task that was created or edited
  • edit_description (dict mapping str to object or None) – The dictionary containing data about what was edited in the task. Its keys correspond to the fields of EditDescriptionForm. None if the task was newly created.
report_withdrawn_status_message(process_class, status_message)

Generate one feed entry for a withdrawn status message for physical processes.

Parameters:
  • process_class (django.contrib.contenttypes.models.ContentType) – the content type of the physical process one of whose statuses was withdrawn
  • status_message (samples.models.StatusMessage) – the status message for the physical process

Form field classes

The following names are found in the module jb_common.utils.views.

class UserField(*, choices=(), **kwargs)

Form field class for the selection of a single user. This can be the new currently responsible person for a sample, or the person you wish to send “My Samples” to.

set_users(user, additional_user=None)

Set the user list shown in the widget. You must call this method (or set_users_without()) in the constructor of the form in which you use this field, otherwise the selection box will remain emtpy. The selection list will consist of all currently active users, plus the given additional user if any.

Parameters:
  • user (django.contrib.auth.models.User) – Thr user who wants to see the user list
  • additional_user (django.contrib.auth.models.User) – Optional additional user to be included into the list. Typically, it is the current user for the process to be edited.
set_users_without(user, excluded_user)

Set the user list shown in the widget. You must call this method (or set_users()) in the constructor of the form in which you use this field, otherwise the selection box will remain emtpy. The selection list will consist of all currently active users, minus the given user.

Parameters:
  • user – Thr user who wants to see the user list
  • excluded_user (django.contrib.auth.models.User) – User to be excluded from the list. Typically, it is the currently logged-in user.
class MultipleUsersField(*args, **kwargs)

Form field class for the selection of zero or more users. This can be the set of members for a particular topic.

set_users(user, additional_users=[])

Set the user list shown in the widget. You must call this method in the constructor of the form in which you use this field, otherwise the selection box will remain emtpy. The selection list will consist of all currently active users, plus the given additional users if any.

Parameters:
  • user – Thr user who wants to see the user list
  • additional_users (iterable of django.contrib.auth.models.User) – Optional additional users to be included into the list. Typically, it is the current users for the topic whose memberships are to be changed.
class TopicField(*, choices=(), **kwargs)

Form field class for the selection of a single topic. This can be the topic for a sample or a sample series, for example.

set_topics(user, additional_topic=None)

Set the topic list shown in the widget. You must call this method in the constructor of the form in which you use this field, otherwise the selection box will remain emtpy. The selection list will consist of all currently active topics, plus the given additional topic if any. The “currently active topics” are all topics with at least one active user amongst its members.

Parameters:
  • user (django.contrib.auth.models.User) – the currently logged-in user
  • additional_topic (jb_common.models.Topic) – Optional additional topic to be included into the list. Typically, it is the current topic of the sample, for example.

Form classes

The following names are found in the module samples.utils.views.

class ProcessForm(user, *args, **kwargs)

Abstract model form class for processes. It ensures that timestamps are not in the future, and that comments contain only allowed Markdown syntax.

Moreover, it defines a field “combined_operator” of the type OperatorField. In the HTML template, you should offer this field to non-staff, and the usual operator/external operator to staff.

Parameters:user (django.contrib.auth.models.User) – the currently logged-in user
is_referentially_valid(samples_form)

Test whether the forms are consistent with each other and with the database. In its current form, it only checks whether the sample is still “alive” at the time of the measurement.

Parameters:samples_form (SampleSelectForm or MultipleSamplesSelectForm) – a bound samples selection form
Returns:whether the forms are consistent with each other and the database
Return type:bool
class DepositionForm(user, data=None, **kwargs)

Model form for depositions (not their layers).

is_referentially_valid(samples_form)

Test whether the forms are consistent with each other and with the database. In its current form, it only checks whether the sample is still “alive” at the time of the measurement.

Parameters:samples_form (SampleSelectForm or MultipleSamplesSelectForm) – a bound samples selection form
Returns:whether the forms are consistent with each other and the database
Return type:bool
class SampleSelectForm(user, process_instance, preset_sample, *args, **kwargs)

Form for the sample selection field. You can only select one sample per process (in contrast to depositions).

Parameters:
  • user (django.contrib.auth.models.User) – the current user
  • process_instance (samples.models.Process) – the process instance to be edited, or None if a new is about to be created
  • preset_sample (samples.models.Sample) – the sample to which the process should be appended when creating a new process; see utils.extract_preset_sample
class DepositionSamplesForm(user, deposition, preset_sample, data=None, **kwargs)

Form for the list selection of samples that took part in the deposition. This form has the special behaviour that it prevents changing the samples when editing an existing process.

class EditDescriptionForm(*args, **kwargs)

Form for letting the user enter a short description of the changes they made.

Plots

The following names are found in the module samples.utils.plots.

exception PlotError

Raised if an error occurs while generating a plot. Usually, it is raised in samples.models.Process.draw_plot() and caught in samples.views.plots.show_plot().

read_plot_file_beginning_at_line_number(filename, columns, start_line_number, end_line_number=None, separator=None)

Read a datafile and returns the content of selected columns beginning at start_line_number. You shouldn’t use this function directly. Use the specific functions instead.

Parameters:
  • filename (str) – full path to the data file
  • columns (list of int) – the columns that should be read.
  • start_line_number (int) – the line number where the data starts
  • end_line_number (int or None) – the line number where the record should end. The default is None, means till end of file.
  • separator (str or None) – the separator which separates the values from each other. Default is None
Returns:

List of all columns. Every column is represented as a list of floating point values.

Return type:

list of list of float

Raises:

PlotError – if something wents wrong with interpreting the file (I/O, unparseble data)

read_plot_file_beginning_after_start_value(filename, columns, start_value, end_value='', separator=None)

Read a datafile and return the content of selected columns after the start_value was detected. You shouldn’t use this function directly. Use the specific functions instead.

Parameters:
  • filename (str) – full path to the data file
  • columns (list of int) – the columns that should be read.
  • start_value (str) – the start_value indicates the line after the data should be read
  • end_value (str) – the end_value marks the line where the record should end. The default is the empty string
  • separator (str or None) – the separator which separates the values from each other. Default is None
Returns:

List of all columns. Every column is represented as a list of floating point values.

Return type:

list of list of float

Raises:

PlotError – if something wents wrong with interpreting the file (I/O, unparseble data)

URLs

The following name is found in the module samples.utils.urls.

class PatternGenerator(url_patterns, views_prefix, app_label=None)

This class helps to build URL pattern lists for physical processes. You instantiate it once in your URLconf file. Then, you add URLs by calling physical_process for every physical process:

pattern_generator = PatternGenerator(urlpatterns, "institute.views.samples")
pattern_generator.deposition("ClusterToolDeposition", views={"add", "edit"})
pattern_generator.deposition("FiveChamberDeposition", "5-chamber_depositions")
pattern_generator.physical_process("PDSMeasurement", "number")
pattern_generator.physical_process("Substrate", views={"edit"})

Important: Various places of JuliaBase assume that the URL patterns of physical processes reside in a namespace which has the same name as the app which holds the associated model classes. So take care that this is the case!

Parameters:
  • url_patterns (list of url() instances) – The URL patterns to populate in situ.
  • views_prefix (str) – the prefix for the view functions as a Python path, e.g. "my_app.views.samples"
  • app_label (str) – The label of the app to which the generated URLs will belong to. Defaults to the first component of views_prefix.
deposition(class_name, url_name=None, views={'edit', 'add', 'lab_notebook'})

Add URLs for the views of the deposition process class_name. This is a shorthand for physical_process with defaults optimized for depositions: identifying_field is "number", and the views include a lab notebook.

Parameters:
  • class_name (str) – Name of the deposition class, e.g. "FiveChamberDeposition".
  • url_name (str) – The URL path component to be used for this deposition. By default, this is the class name converted to underscores notation, with an “s” appended, e.g. "thickness_measurements".
  • views (set of str) – The view functions for which URLs should be generated. You may choose from "add", "edit", "custom_show", and "lab_notebook".
physical_process(class_name, identifying_field=None, url_name=None, views={'edit', 'add'})

Add URLs for the views of the physical process class_name. For the “add” and the “edit” view, an edit(request, process_class_name_id) function must exist. In case of “add”, None is passed as the second parameter. For the “custom show” view, a show(request, process_class_name_id) function must exist. If there is an identifying_field, this is used for the second parameter name instead. If no URL for a custom show view is requested, a default one is generated using a generic view function (which is mostly sufficient).

Parameters:
  • class_name (str) – Name of the physical process class, e.g. "ThicknessMeasurement".
  • identifying_field (str) – If applicable, name of the model field which serves as “poor man’s” primary key. If not given, the field name is derived from the model’s JBMeta class, and if this fails, id is used. This parameter is deprecated and will be removed in JuliaBase 1.2.
  • url_name (str) – The URL path component to be used for this process. By default, this is the class name converted to underscores notation, with an “s” appended, e.g. "thickness_measurements". It may contain slashs.
  • views (set of str) – The view functions for which URLs should be generated. You may choose from "add", "edit", "custom_show", and "lab_notebook".