Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
    • Switch to GitLab Next
  • Sign in / Register
wiki
wiki
  • Project overview
    • Project overview
    • Details
    • Activity
  • Issues 19
    • Issues 19
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
    • Iterations
  • Requirements
    • Requirements
    • List
  • Operations
    • Operations
    • Incidents
  • Analytics
    • Analytics
    • Insights
    • Issue
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • Members
    • Members
  • Collapse sidebar
  • Activity
  • Create a new issue
  • Issue Boards
  • openlp
  • wikiwiki
  • Wiki
    • Development
  • Structure

Last edited by Raoul Snyman Oct 14, 2019
Page history

Structure

It's always difficult to determine how to structure an application, not only before starting the application, but also WHILE developing your application. OpenLP has grown organically over the last 10 years, and this means that the codebase has become unwieldy with a number of circular imports and other questionable coding practices.

This page will hopefully help us to structure OpenLP's codebase better.

Module Structure

  • openlp
    • core
      • api
      • display
      • common
      • projector
      • mediaplayers
      • ui
      • widgets
    • plugins
      • songs
      • bibles
      • presentations
      • media
      • images
      • custom

Tips

  • Keep __init__.py fairly empty. One of the issues we've had in the past is importing a lot of things into __init__.py in an effort to make import statements shorter, but this has only caused more problems than it is worth, including the terror of coding: circular imports.
  • Keep import statements to a minimum. Only include the imports you absolutely need.
  • Use as full of a module path as possible in your import statements. This ties in with the first tip. Rather import from openlp.core.common.registry (avoiding circular imports) than importing openlp.core.common.registry contents into openlp.core.common and then importing from openlp.core.common.

GUI vs Library

Always keep GUI and Library code separate. The easiest way to do this is to make sure that all windows, dialogs, widgets and message boxes originate from another GUI element.

For example, if you encounter an error in your networking code while the user is downloading a Bible, rather let an exception bubble up to the import wizard and let the wizard handle the exception and show an error message.

Multiple Inheritance Uglies

Single inheritance is always simple. You have one parent class, and calling super() just calls the parent's __init__() method. Python supports multiple inheritance, and this can get quite tricky.

For more information on multiple inheritance and the super() function in Python, I highly recommend reading the following article: http://www.artima.com/weblogs/viewpost.jsp?thread=281127

Base Classes vs Mixins

In the OpenLP codebase, we make use of both base classes and mixins. The key difference between these two is that a mixin does not have an __init__() method. If you add an __init__() method to a mixin, you will encounter a number of inheritance-related error messages.

When adding mixins to your classes, make sure that you always add them LAST. For example:

class AlertsManager(QtCore.QObject, RegistryBase, LogMixin, RegistryProperties):
    pass
  • QtCore.QObject
    This is a PyQt5 class. PyQt5 classes (thankfully) are already configured to handle multiple inheritance correctly. Place PyQt5 classes first where possible.
  • RegistryBase
    This is a Python base class. This class will need the correct __init__() method in order to handle multiple inheritance correctly. Python base classes should be placed after PyQt5 classes.
  • LogMixin
    This is a Python mixin class. Mixin classes should ALWAYS be placed last.
  • RegistryProperties
    Also a mixin class.

Within OpenLP, the Ui_{name} classes are also mixins. Make sure they also go last.

Here's an example of a UI widget that inherits from PyQt5, our own base class, and a bunch of mixins. Take note of the order of the inherited classes.

class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixin, RegistryProperties):
    pass
Clone repository
  • Addendum
  • Brand_Guidelines
  • Classes_Plugin
  • Code Structure
  • Configuring_SSH_Keys_on_Linux_and_Mac_OS_X
  • Configuring_SSH_Keys_on_Windows
  • Creating a Study Bible for OpenLP
  • Custom Stage Views
  • Development of Icons
  • Development
    • Branching_And_Merging_Standards
    • Coding_Standards
    • Convert from Bazaar to Git
    • Core_API_Framework
    • EasySlides_ _Song_Data_Format
    • EasyWorship_ _Song_Data_Format
View All Pages