Rudimentary python3 support

This commit is contained in:
BeryJu.org Deployment Account 2017-01-21 17:49:38 +01:00
parent 39d083eae7
commit 83a8d954e0
14 changed files with 81 additions and 77 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
*.pyc *.pyc
/netbox/netbox/configuration.py /netbox/netbox/configuration.py
/netbox/netbox/ldap_config.py
/netbox/static /netbox/static
.idea .idea
/*.sh /*.sh

View File

@ -9,6 +9,9 @@ env:
language: python language: python
python: python:
- "2.7" - "2.7"
- "3.4"
- "3.5"
- "3.6"
install: install:
- pip install -r requirements.txt - pip install -r requirements.txt
- pip install pep8 - pip install pep8

View File

@ -51,7 +51,7 @@ class Provider(CreatedUpdatedModel, CustomFieldModel):
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
def __unicode__(self): def __str__(self):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
@ -78,7 +78,7 @@ class CircuitType(models.Model):
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
def __unicode__(self): def __str__(self):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
@ -105,7 +105,7 @@ class Circuit(CreatedUpdatedModel, CustomFieldModel):
ordering = ['provider', 'cid'] ordering = ['provider', 'cid']
unique_together = ['provider', 'cid'] unique_together = ['provider', 'cid']
def __unicode__(self): def __str__(self):
return u'{} {}'.format(self.provider, self.cid) return u'{} {}'.format(self.provider, self.cid)
def get_absolute_url(self): def get_absolute_url(self):
@ -156,7 +156,7 @@ class CircuitTermination(models.Model):
ordering = ['circuit', 'term_side'] ordering = ['circuit', 'term_side']
unique_together = ['circuit', 'term_side'] unique_together = ['circuit', 'term_side']
def __unicode__(self): def __str__(self):
return u'{} (Side {})'.format(self.circuit, self.get_term_side_display()) return u'{} (Side {})'.format(self.circuit, self.get_term_side_display())
def get_peer_termination(self): def get_peer_termination(self):

View File

@ -13,7 +13,7 @@ from utilities.forms import (
SlugField, SlugField,
) )
from formfields import MACAddressFormField from .formfields import MACAddressFormField
from .models import ( from .models import (
DeviceBay, DeviceBayTemplate, CONNECTION_STATUS_CHOICES, CONNECTION_STATUS_PLANNED, CONNECTION_STATUS_CONNECTED, DeviceBay, DeviceBayTemplate, CONNECTION_STATUS_CHOICES, CONNECTION_STATUS_PLANNED, CONNECTION_STATUS_CONNECTED,
ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceRole, DeviceType, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceRole, DeviceType,

View File

@ -222,7 +222,7 @@ class Site(CreatedUpdatedModel, CustomFieldModel):
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
def __unicode__(self): def __str__(self):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
@ -282,7 +282,7 @@ class RackGroup(models.Model):
['site', 'slug'], ['site', 'slug'],
] ]
def __unicode__(self): def __str__(self):
return u'{} - {}'.format(self.site.name, self.name) return u'{} - {}'.format(self.site.name, self.name)
def get_absolute_url(self): def get_absolute_url(self):
@ -300,7 +300,7 @@ class RackRole(models.Model):
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
def __unicode__(self): def __str__(self):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
@ -343,7 +343,7 @@ class Rack(CreatedUpdatedModel, CustomFieldModel):
['site', 'facility_id'], ['site', 'facility_id'],
] ]
def __unicode__(self): def __str__(self):
return self.display_name return self.display_name
def get_absolute_url(self): def get_absolute_url(self):
@ -487,7 +487,7 @@ class Manufacturer(models.Model):
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
def __unicode__(self): def __str__(self):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
@ -538,7 +538,7 @@ class DeviceType(models.Model, CustomFieldModel):
['manufacturer', 'slug'], ['manufacturer', 'slug'],
] ]
def __unicode__(self): def __str__(self):
return self.model return self.model
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -619,7 +619,7 @@ class ConsolePortTemplate(models.Model):
ordering = ['device_type', 'name'] ordering = ['device_type', 'name']
unique_together = ['device_type', 'name'] unique_together = ['device_type', 'name']
def __unicode__(self): def __str__(self):
return self.name return self.name
@ -634,7 +634,7 @@ class ConsoleServerPortTemplate(models.Model):
ordering = ['device_type', 'name'] ordering = ['device_type', 'name']
unique_together = ['device_type', 'name'] unique_together = ['device_type', 'name']
def __unicode__(self): def __str__(self):
return self.name return self.name
@ -649,7 +649,7 @@ class PowerPortTemplate(models.Model):
ordering = ['device_type', 'name'] ordering = ['device_type', 'name']
unique_together = ['device_type', 'name'] unique_together = ['device_type', 'name']
def __unicode__(self): def __str__(self):
return self.name return self.name
@ -664,7 +664,7 @@ class PowerOutletTemplate(models.Model):
ordering = ['device_type', 'name'] ordering = ['device_type', 'name']
unique_together = ['device_type', 'name'] unique_together = ['device_type', 'name']
def __unicode__(self): def __str__(self):
return self.name return self.name
@ -721,7 +721,7 @@ class InterfaceTemplate(models.Model):
ordering = ['device_type', 'name'] ordering = ['device_type', 'name']
unique_together = ['device_type', 'name'] unique_together = ['device_type', 'name']
def __unicode__(self): def __str__(self):
return self.name return self.name
@ -736,7 +736,7 @@ class DeviceBayTemplate(models.Model):
ordering = ['device_type', 'name'] ordering = ['device_type', 'name']
unique_together = ['device_type', 'name'] unique_together = ['device_type', 'name']
def __unicode__(self): def __str__(self):
return self.name return self.name
@ -756,7 +756,7 @@ class DeviceRole(models.Model):
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
def __unicode__(self): def __str__(self):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
@ -776,7 +776,7 @@ class Platform(models.Model):
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
def __unicode__(self): def __str__(self):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
@ -828,7 +828,7 @@ class Device(CreatedUpdatedModel, CustomFieldModel):
ordering = ['name'] ordering = ['name']
unique_together = ['rack', 'position', 'face'] unique_together = ['rack', 'position', 'face']
def __unicode__(self): def __str__(self):
return self.display_name return self.display_name
def get_absolute_url(self): def get_absolute_url(self):
@ -982,7 +982,7 @@ class ConsolePort(models.Model):
ordering = ['device', 'name'] ordering = ['device', 'name']
unique_together = ['device', 'name'] unique_together = ['device', 'name']
def __unicode__(self): def __str__(self):
return self.name return self.name
# Used for connections export # Used for connections export
@ -1023,7 +1023,7 @@ class ConsoleServerPort(models.Model):
class Meta: class Meta:
unique_together = ['device', 'name'] unique_together = ['device', 'name']
def __unicode__(self): def __str__(self):
return self.name return self.name
@ -1041,7 +1041,7 @@ class PowerPort(models.Model):
ordering = ['device', 'name'] ordering = ['device', 'name']
unique_together = ['device', 'name'] unique_together = ['device', 'name']
def __unicode__(self): def __str__(self):
return self.name return self.name
# Used for connections export # Used for connections export
@ -1076,7 +1076,7 @@ class PowerOutlet(models.Model):
class Meta: class Meta:
unique_together = ['device', 'name'] unique_together = ['device', 'name']
def __unicode__(self): def __str__(self):
return self.name return self.name
@ -1099,7 +1099,7 @@ class Interface(models.Model):
ordering = ['device', 'name'] ordering = ['device', 'name']
unique_together = ['device', 'name'] unique_together = ['device', 'name']
def __unicode__(self): def __str__(self):
return self.name return self.name
def clean(self): def clean(self):
@ -1189,7 +1189,7 @@ class DeviceBay(models.Model):
ordering = ['device', 'name'] ordering = ['device', 'name']
unique_together = ['device', 'name'] unique_together = ['device', 'name']
def __unicode__(self): def __str__(self):
return u'{} - {}'.format(self.device.name, self.name) return u'{} - {}'.format(self.device.name, self.name)
def clean(self): def clean(self):
@ -1223,5 +1223,5 @@ class Module(models.Model):
ordering = ['device__id', 'parent__id', 'name'] ordering = ['device__id', 'parent__id', 'name']
unique_together = ['device', 'parent', 'name'] unique_together = ['device', 'parent', 'name']
def __unicode__(self): def __str__(self):
return self.name return self.name

View File

@ -114,7 +114,7 @@ class CustomField(models.Model):
class Meta: class Meta:
ordering = ['weight', 'name'] ordering = ['weight', 'name']
def __unicode__(self): def __str__(self):
return self.label or self.name.replace('_', ' ').capitalize() return self.label or self.name.replace('_', ' ').capitalize()
def serialize_value(self, value): def serialize_value(self, value):
@ -164,7 +164,7 @@ class CustomFieldValue(models.Model):
ordering = ['obj_type', 'obj_id'] ordering = ['obj_type', 'obj_id']
unique_together = ['field', 'obj_type', 'obj_id'] unique_together = ['field', 'obj_type', 'obj_id']
def __unicode__(self): def __str__(self):
return u'{} {}'.format(self.obj, self.field) return u'{} {}'.format(self.obj, self.field)
@property @property
@ -193,7 +193,7 @@ class CustomFieldChoice(models.Model):
ordering = ['field', 'weight', 'value'] ordering = ['field', 'weight', 'value']
unique_together = ['field', 'value'] unique_together = ['field', 'value']
def __unicode__(self): def __str__(self):
return self.value return self.value
def clean(self): def clean(self):
@ -217,7 +217,7 @@ class Graph(models.Model):
class Meta: class Meta:
ordering = ['type', 'weight', 'name'] ordering = ['type', 'weight', 'name']
def __unicode__(self): def __str__(self):
return self.name return self.name
def embed_url(self, obj): def embed_url(self, obj):
@ -245,7 +245,7 @@ class ExportTemplate(models.Model):
['content_type', 'name'] ['content_type', 'name']
] ]
def __unicode__(self): def __str__(self):
return u'{}: {}'.format(self.content_type, self.name) return u'{}: {}'.format(self.content_type, self.name)
def to_response(self, context_dict, filename): def to_response(self, context_dict, filename):
@ -278,7 +278,7 @@ class TopologyMap(models.Model):
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
def __unicode__(self): def __str__(self):
return self.name return self.name
@property @property
@ -344,7 +344,7 @@ class UserAction(models.Model):
class Meta: class Meta:
ordering = ['-time'] ordering = ['-time']
def __unicode__(self): def __str__(self):
if self.message: if self.message:
return u'{} {}'.format(self.user, self.message) return u'{} {}'.format(self.user, self.message)
return u'{} {} {}'.format(self.user, self.get_action_display(), self.content_type) return u'{} {} {}'.format(self.user, self.get_action_display(), self.content_type)

View File

@ -1,4 +1,4 @@
#!/usr/bin/python #!/usr/bin/python3
# This script will generate a random 50-character string suitable for use as a SECRET_KEY. # This script will generate a random 50-character string suitable for use as a SECRET_KEY.
import os import os
import random import random

View File

@ -89,7 +89,7 @@ class VRF(CreatedUpdatedModel, CustomFieldModel):
verbose_name = 'VRF' verbose_name = 'VRF'
verbose_name_plural = 'VRFs' verbose_name_plural = 'VRFs'
def __unicode__(self): def __str__(self):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
@ -120,7 +120,7 @@ class RIR(models.Model):
verbose_name = 'RIR' verbose_name = 'RIR'
verbose_name_plural = 'RIRs' verbose_name_plural = 'RIRs'
def __unicode__(self): def __str__(self):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
@ -142,7 +142,7 @@ class Aggregate(CreatedUpdatedModel, CustomFieldModel):
class Meta: class Meta:
ordering = ['family', 'prefix'] ordering = ['family', 'prefix']
def __unicode__(self): def __str__(self):
return str(self.prefix) return str(self.prefix)
def get_absolute_url(self): def get_absolute_url(self):
@ -216,7 +216,7 @@ class Role(models.Model):
class Meta: class Meta:
ordering = ['weight', 'name'] ordering = ['weight', 'name']
def __unicode__(self): def __str__(self):
return self.name return self.name
@property @property
@ -292,7 +292,7 @@ class Prefix(CreatedUpdatedModel, CustomFieldModel):
ordering = ['vrf', 'family', 'prefix'] ordering = ['vrf', 'family', 'prefix']
verbose_name_plural = 'prefixes' verbose_name_plural = 'prefixes'
def __unicode__(self): def __str__(self):
return str(self.prefix) return str(self.prefix)
def get_absolute_url(self): def get_absolute_url(self):
@ -409,7 +409,7 @@ class IPAddress(CreatedUpdatedModel, CustomFieldModel):
verbose_name = 'IP address' verbose_name = 'IP address'
verbose_name_plural = 'IP addresses' verbose_name_plural = 'IP addresses'
def __unicode__(self): def __str__(self):
return str(self.address) return str(self.address)
def get_absolute_url(self): def get_absolute_url(self):
@ -486,7 +486,7 @@ class VLANGroup(models.Model):
verbose_name = 'VLAN group' verbose_name = 'VLAN group'
verbose_name_plural = 'VLAN groups' verbose_name_plural = 'VLAN groups'
def __unicode__(self): def __str__(self):
return u'{} - {}'.format(self.site.name, self.name) return u'{} - {}'.format(self.site.name, self.name)
def get_absolute_url(self): def get_absolute_url(self):
@ -524,7 +524,7 @@ class VLAN(CreatedUpdatedModel, CustomFieldModel):
verbose_name = 'VLAN' verbose_name = 'VLAN'
verbose_name_plural = 'VLANs' verbose_name_plural = 'VLANs'
def __unicode__(self): def __str__(self):
return self.display_name return self.display_name
def get_absolute_url(self): def get_absolute_url(self):
@ -576,5 +576,5 @@ class Service(CreatedUpdatedModel):
ordering = ['device', 'protocol', 'port'] ordering = ['device', 'protocol', 'port']
unique_together = ['device', 'protocol', 'port'] unique_together = ['device', 'protocol', 'port']
def __unicode__(self): def __str__(self):
return u'{} ({}/{})'.format(self.name, self.port, self.get_protocol_display()) return u'{} ({}/{})'.format(self.name, self.port, self.get_protocol_display())

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
import os import os
import sys import sys

View File

@ -6,7 +6,7 @@ from django.contrib.messages import constants as messages
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
try: try:
import configuration import netbox.configuration
except ImportError: except ImportError:
raise ImproperlyConfigured("Configuration file is not present. Please define netbox/netbox/configuration.py per " raise ImproperlyConfigured("Configuration file is not present. Please define netbox/netbox/configuration.py per "
"the documentation.") "the documentation.")
@ -17,40 +17,40 @@ VERSION = '1.8.3-dev'
# Import local configuration # Import local configuration
for setting in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY']: for setting in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY']:
try: try:
globals()[setting] = getattr(configuration, setting) globals()[setting] = getattr(netbox.configuration, setting)
except AttributeError: except AttributeError:
raise ImproperlyConfigured("Mandatory setting {} is missing from configuration.py. Please define it per the " raise ImproperlyConfigured("Mandatory setting {} is missing from configuration.py. Please define it per the "
"documentation.".format(setting)) "documentation.".format(setting))
# Default configurations # Default configurations
ADMINS = getattr(configuration, 'ADMINS', []) ADMINS = getattr(netbox.configuration, 'ADMINS', [])
DEBUG = getattr(configuration, 'DEBUG', False) DEBUG = getattr(netbox.configuration, 'DEBUG', False)
EMAIL = getattr(configuration, 'EMAIL', {}) EMAIL = getattr(netbox.configuration, 'EMAIL', {})
LOGIN_REQUIRED = getattr(configuration, 'LOGIN_REQUIRED', False) LOGIN_REQUIRED = getattr(netbox.configuration, 'LOGIN_REQUIRED', False)
BASE_PATH = getattr(configuration, 'BASE_PATH', '') BASE_PATH = getattr(netbox.configuration, 'BASE_PATH', '')
if BASE_PATH: if BASE_PATH:
BASE_PATH = BASE_PATH.strip('/') + '/' # Enforce trailing slash only BASE_PATH = BASE_PATH.strip('/') + '/' # Enforce trailing slash only
MAINTENANCE_MODE = getattr(configuration, 'MAINTENANCE_MODE', False) MAINTENANCE_MODE = getattr(netbox.configuration, 'MAINTENANCE_MODE', False)
PAGINATE_COUNT = getattr(configuration, 'PAGINATE_COUNT', 50) PAGINATE_COUNT = getattr(netbox.configuration, 'PAGINATE_COUNT', 50)
NETBOX_USERNAME = getattr(configuration, 'NETBOX_USERNAME', '') NETBOX_USERNAME = getattr(netbox.configuration, 'NETBOX_USERNAME', '')
NETBOX_PASSWORD = getattr(configuration, 'NETBOX_PASSWORD', '') NETBOX_PASSWORD = getattr(netbox.configuration, 'NETBOX_PASSWORD', '')
TIME_ZONE = getattr(configuration, 'TIME_ZONE', 'UTC') TIME_ZONE = getattr(netbox.configuration, 'TIME_ZONE', 'UTC')
DATE_FORMAT = getattr(configuration, 'DATE_FORMAT', 'N j, Y') DATE_FORMAT = getattr(netbox.configuration, 'DATE_FORMAT', 'N j, Y')
SHORT_DATE_FORMAT = getattr(configuration, 'SHORT_DATE_FORMAT', 'Y-m-d') SHORT_DATE_FORMAT = getattr(netbox.configuration, 'SHORT_DATE_FORMAT', 'Y-m-d')
TIME_FORMAT = getattr(configuration, 'TIME_FORMAT', 'g:i a') TIME_FORMAT = getattr(netbox.configuration, 'TIME_FORMAT', 'g:i a')
SHORT_TIME_FORMAT = getattr(configuration, 'SHORT_TIME_FORMAT', 'H:i:s') SHORT_TIME_FORMAT = getattr(netbox.configuration, 'SHORT_TIME_FORMAT', 'H:i:s')
DATETIME_FORMAT = getattr(configuration, 'DATETIME_FORMAT', 'N j, Y g:i a') DATETIME_FORMAT = getattr(netbox.configuration, 'DATETIME_FORMAT', 'N j, Y g:i a')
SHORT_DATETIME_FORMAT = getattr(configuration, 'SHORT_DATETIME_FORMAT', 'Y-m-d H:i') SHORT_DATETIME_FORMAT = getattr(netbox.configuration, 'SHORT_DATETIME_FORMAT', 'Y-m-d H:i')
BANNER_TOP = getattr(configuration, 'BANNER_TOP', False) BANNER_TOP = getattr(netbox.configuration, 'BANNER_TOP', False)
BANNER_BOTTOM = getattr(configuration, 'BANNER_BOTTOM', False) BANNER_BOTTOM = getattr(netbox.configuration, 'BANNER_BOTTOM', False)
PREFER_IPV4 = getattr(configuration, 'PREFER_IPV4', False) PREFER_IPV4 = getattr(netbox.configuration, 'PREFER_IPV4', False)
ENFORCE_GLOBAL_UNIQUE = getattr(configuration, 'ENFORCE_GLOBAL_UNIQUE', False) ENFORCE_GLOBAL_UNIQUE = getattr(netbox.configuration, 'ENFORCE_GLOBAL_UNIQUE', False)
CSRF_TRUSTED_ORIGINS = ALLOWED_HOSTS CSRF_TRUSTED_ORIGINS = ALLOWED_HOSTS
# Attempt to import LDAP configuration if it has been defined # Attempt to import LDAP configuration if it has been defined
LDAP_IGNORE_CERT_ERRORS = False LDAP_IGNORE_CERT_ERRORS = False
try: try:
from ldap_config import * from netbox.ldap_config import *
LDAP_CONFIGURED = True LDAP_CONFIGURED = True
except ImportError: except ImportError:
LDAP_CONFIGURED = False LDAP_CONFIGURED = False
@ -79,9 +79,9 @@ if LDAP_CONFIGURED:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Database # Database
configuration.DATABASE.update({'ENGINE': 'django.db.backends.postgresql'}) netbox.configuration.DATABASE.update({'ENGINE': 'django.db.backends.postgresql'})
DATABASES = { DATABASES = {
'default': configuration.DATABASE, 'default': netbox.configuration.DATABASE,
} }
# Email # Email

View File

@ -2,7 +2,7 @@ from django.conf import settings
from django.conf.urls import include, url from django.conf.urls import include, url
from django.contrib import admin from django.contrib import admin
from views import home, handle_500, trigger_500 from netbox.views import home, handle_500, trigger_500
from users.views import login, logout from users.views import login, logout

View File

@ -76,7 +76,7 @@ class UserKey(CreatedUpdatedModel):
self.__initial_public_key = self.public_key self.__initial_public_key = self.public_key
self.__initial_master_key_cipher = self.master_key_cipher self.__initial_master_key_cipher = self.master_key_cipher
def __unicode__(self): def __str__(self):
return self.user.username return self.user.username
def clean(self, *args, **kwargs): def clean(self, *args, **kwargs):
@ -186,7 +186,7 @@ class SecretRole(models.Model):
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
def __unicode__(self): def __str__(self):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
@ -227,7 +227,7 @@ class Secret(CreatedUpdatedModel):
self.plaintext = kwargs.pop('plaintext', None) self.plaintext = kwargs.pop('plaintext', None)
super(Secret, self).__init__(*args, **kwargs) super(Secret, self).__init__(*args, **kwargs)
def __unicode__(self): def __str__(self):
if self.role and self.device: if self.role and self.device:
return u'{} for {}'.format(self.role, self.device) return u'{} for {}'.format(self.role, self.device)
return u'Secret' return u'Secret'

View File

@ -17,7 +17,7 @@ class TenantGroup(models.Model):
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
def __unicode__(self): def __str__(self):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
@ -39,7 +39,7 @@ class Tenant(CreatedUpdatedModel, CustomFieldModel):
class Meta: class Meta:
ordering = ['group', 'name'] ordering = ['group', 'name']
def __unicode__(self): def __str__(self):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):

View File

@ -10,7 +10,7 @@ from utilities.views import (
BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView, BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
) )
from models import Tenant, TenantGroup from .models import Tenant, TenantGroup
from . import filters, forms, tables from . import filters, forms, tables