<commit_before>import re

from mptt.forms import TreeNodeChoiceField

from django import forms
from django.contrib.postgres.forms.array import SimpleArrayField
from django.core.exceptions import ValidationError
from django.db.models import Count, Q

from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
from ipam.models import IPAddress
from tenancy.models import Tenant
from utilities.forms import (
    APISelect, add_blank_choice, ArrayFieldSelectMultiple, BootstrapMixin, BulkEditForm, BulkImportForm, CommentField,
    CSVDataField, ExpandableNameField, FilterChoiceField, FlexibleModelChoiceField, Livesearch, SelectWithDisabled,
    SmallTextarea, SlugField, FilterTreeNodeMultipleChoiceField,
)

from .formfields import MACAddressFormField
from .models import (
    DeviceBay, DeviceBayTemplate, CONNECTION_STATUS_CHOICES, CONNECTION_STATUS_PLANNED, CONNECTION_STATUS_CONNECTED,
    ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceRole, DeviceType,
    Interface, IFACE_FF_CHOICES, IFACE_FF_LAG, IFACE_ORDERING_CHOICES, InterfaceConnection, InterfaceTemplate,
    Manufacturer, Module, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, RACK_TYPE_CHOICES,
    RACK_WIDTH_CHOICES, Rack, RackGroup, RackReservation, RackRole, Region, Site, STATUS_CHOICES, SUBDEVICE_ROLE_CHILD,
    VIRTUAL_IFACE_TYPES
)


FORM_STATUS_CHOICES = [
    ['', '---------'],
]

FORM_STATUS_CHOICES += STATUS_CHOICES

DEVICE_BY_PK_RE = '{\d+\}'


def get_device_by_name_or_pk(name):
    """
    Attempt to retrieve a device by either its name or primary key ('{pk}').
    """
    if re.match(DEVICE_BY_PK_RE, name):
        pk = name.strip('{}')
        device = Device.objects.get(pk=pk)
    else:
        device = Device.objects.get(name=name)
    return device


def validate_connection_status(value):
    """
    Custom validator for connection statuses. value must be either "planned" or "connected" (case-insensitive).
    """
    if value.lower() not in ['planned', 'connected']:
        raise ValidationError('Invalid connection status ({}); must be either "planned" or "connected".'.format(value))


class DeviceComponentForm(BootstrapMixin, forms.Form):
    """
    Allow inclusion of the parent device as context for limiting field choices.
    """
    def __init__(self, device, *args, **kwargs):
        self.device = device
        super(DeviceComponentForm, self).__init__(*args, **kwargs)


#
# Regions
#

class RegionForm(BootstrapMixin, forms.ModelForm):
    slug = SlugField()

    class Meta:
        model = Region
        fields = ['parent', 'name', 'slug']


#
# Sites
#

class SiteForm(BootstrapMixin, CustomFieldForm):
    region = TreeNodeChoiceField(queryset=Region.objects.all())
    slug = SlugField()
    comments = CommentField()

    class Meta:
        model = Site
        fields = [
            'name', 'slug', 'region', 'tenant', 'facility', 'asn', 'physical_address', 'shipping_address',
            'contact_name', 'contact_phone', 'contact_email', 'comments',
        ]
        widgets = {
            'physical_address': SmallTextarea(attrs={'rows': 3}),
            'shipping_address': SmallTextarea(attrs={'rows': 3}),
        }
        help_texts = {
            'name': "Full name of the site",
            'facility': "Data center provider and facility (e.g. Equinix NY7)",
            'asn': "BGP autonomous system number",
            'physical_address': "Physical location of the building (e.g. for GPS)",
            'shipping_address': "If different from the physical address"
        }


class SiteFromCSVForm(forms.ModelForm):
    region = forms.ModelChoiceField(<commit_msg>Fixes #937: Region assignment should be optional when creating a site<commit_after>import re

from mptt.forms import TreeNodeChoiceField

from django import forms
from django.contrib.postgres.forms.array import SimpleArrayField
from django.core.exceptions import ValidationError
from django.db.models import Count, Q

from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
from ipam.models import IPAddress
from tenancy.models import Tenant
from utilities.forms import (
    APISelect, add_blank_choice, ArrayFieldSelectMultiple, BootstrapMixin, BulkEditForm, BulkImportForm, CommentField,
    CSVDataField, ExpandableNameField, FilterChoiceField, FlexibleModelChoiceField, Livesearch, SelectWithDisabled,
    SmallTextarea, SlugField, FilterTreeNodeMultipleChoiceField,
)

from .formfields import MACAddressFormField
from .models import (
    DeviceBay, DeviceBayTemplate, CONNECTION_STATUS_CHOICES, CONNECTION_STATUS_PLANNED, CONNECTION_STATUS_CONNECTED,
    ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceRole, DeviceType,
    Interface, IFACE_FF_CHOICES, IFACE_FF_LAG, IFACE_ORDERING_CHOICES, InterfaceConnection, InterfaceTemplate,
    Manufacturer, Module, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, RACK_TYPE_CHOICES,
    RACK_WIDTH_CHOICES, Rack, RackGroup, RackReservation, RackRole, Region, Site, STATUS_CHOICES, SUBDEVICE_ROLE_CHILD,
    VIRTUAL_IFACE_TYPES
)


FORM_STATUS_CHOICES = [
    ['', '---------'],
]

FORM_STATUS_CHOICES += STATUS_CHOICES

DEVICE_BY_PK_RE = '{\d+\}'


def get_device_by_name_or_pk(name):
    """
    Attempt to retrieve a device by either its name or primary key ('{pk}').
    """
    if re.match(DEVICE_BY_PK_RE, name):
        pk = name.strip('{}')
        device = Device.objects.get(pk=pk)
    else:
        device = Device.objects.get(name=name)
    return device


def validate_connection_status(value):
    """
    Custom validator for connection statuses. value must be either "planned" or "connected" (case-insensitive).
    """
    if value.lower() not in ['planned', 'connected']:
        raise ValidationError('Invalid connection status ({}); must be either "planned" or "connected".'.format(value))


class DeviceComponentForm(BootstrapMixin, forms.Form):
    """
    Allow inclusion of the parent device as context for limiting field choices.
    """
    def __init__(self, device, *args, **kwargs):
        self.device = device
        super(DeviceComponentForm, self).__init__(*args, **kwargs)


#
# Regions
#

class RegionForm(BootstrapMixin, forms.ModelForm):
    slug = SlugField()

    class Meta:
        model = Region
        fields = ['parent', 'name', 'slug']


#
# Sites
#

class SiteForm(BootstrapMixin, CustomFieldForm):
    region = TreeNodeChoiceField(queryset=Region.objects.all(), required=False)
    slug = SlugField()
    comments = CommentField()

    class Meta:
        model = Site
        fields = [
            'name', 'slug', 'region', 'tenant', 'facility', 'asn', 'physical_address', 'shipping_address',
            'contact_name', 'contact_phone', 'contact_email', 'comments',
        ]
        widgets = {
            'physical_address': SmallTextarea(attrs={'rows': 3}),
            'shipping_address': SmallTextarea(attrs={'rows': 3}),
        }
        help_texts = {
            'name': "Full name of the site",
            'facility': "Data center provider and facility (e.g. Equinix NY7)",
            'asn': "BGP autonomous system number",
            'physical_address': "Physical location of the building (e.g. for GPS)",
            'shipping_address': "If different from the physical address"
        }


class SiteFromCSVForm(forms.ModelForm):
    region = forms.ModelChoiceField(
{'fraction_non_alphanumeric': 0.10370567848573714, 'fraction_numerical': 0.0011996800853105837, 'mean_word_length': 3.9754641909814326, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6051865', 'n_tokens_mistral': 2248, 'n_tokens_neox': 2166, 'n_words': 562}