text: #!/usr/bin/env python3
  # -*- coding: utf-8 -*-
  # This file was automatically generated by ../etl_2020/census_etl/spec_scanner.py on Fri Oct 30 14:46:58 2020
  # Command line: ../etl_2020/census_etl/spec_scanner.py ../etl_2020/mdf/2020 Microdata Detail File Specification v8_05292020.docx --output_parser ../das_decennial/programs/writer/cef_2020/mdf_validator_classes.py --tablenames MDF_Person MDF_Unit
  
  # Automatically generated on Fri Oct 30 14:46:58 2020 by /mnt/users/will0555/new-das-vm/das-vm-config/das_decennial/das_framework/ctools/schema/table.py
  
  def leftpad(x,width):
      return ' '*(width-len(str(x)))+str(x)
  
  def between(a,b,c,width):
      if len(b) > width:
          return False
      if '.' in a or '.' in b or '.' in c:
          try:
              return float(a) <= float(b) <= float(c)
          except ValueError:
              pass  # tries to return a float but might have weird input like 1.1.0 which will be compared traditionally instead
      b = b.replace(' ', '0')
      return leftpad(a,width) <= leftpad(b,width) <= leftpad(c,width)
  
  
  def safe_int(i):
      try:
          return int(i)
      except (TypeError, ValueError) as e:
          return None
  
  def safe_float(i):
      try:
          return float(i)
      except (TypeError, ValueError) as e:
          return None
  
  def safe_str(i):
      try:
          return str(i)
      except (TypeError, ValueError) as e:
          return None
  
  
  class MDF_Person_validator:
      @classmethod
      def is_valid_SCHEMA_TYPE_CODE(self,x):
          """Schema Type Code"""
          if x is None or x == "None":
              return False
          return (leftpad(x,3)==leftpad('MPD',3))
      @classmethod
      def is_valid_SCHEMA_BUILD_ID(self,x):
          """Schema Build ID"""
          if x is None or x == "None":
              return False
          return True
      @classmethod
      def is_valid_TABBLKST(self,x):
          """2020 Tabulation State (FIPS)"""
          if x is None or x == "None":
              return False
          return (between('44',x,'51',2)) or (leftpad(x,2)==leftpad('72',2)) or (between('08',x,'13',2)) or (between('53',x,'56',2)) or (between('01',x,'02',2)) or (between('04',x,'06',2)) or (between('15',x,'42',2))
      @classmethod
      def is_valid_TABBLKCOU(self,x):
          """2020 Tabulation County (FIPS)"""
          if x is None or x == "None":
              return False
          return (between('001',x,'840',3))
      @classmethod
      def is_valid_TABTRACTCE(self,x):
          """2020 Tabulation Census Tract"""
          if x is None or x == "None":
              return False
          return (between('000100',x,'998999',6))
      @classmethod
      def is_valid_TABBLKGRPCE(self,x):
          """2020 Census Block Group"""
          if x is None or x == "None":
              return False
          return (between('0',x,'9',1))
      @classmethod
      def is_valid_TABBLK(self,x):
          """2020 Block Number"""
          if x is None or x == "None":
              return False
          return (between('0001',x,'9999',4))
      @classmethod
      def is_valid_EPNUM(self,x):
          """Privacy Edited Person Number"""
          if x is None or x == "None":
              return False
          x = str(x).strip()
          try:
              x = int(x)
          except ValueError:
              return False
          return (0 <= x <= 999999999)
      @classmethod
      def is_valid_RTYPE(self,x):
          """Record Type"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('5',1)) or (leftpad(x,1)==leftpad('3',1))
      @classmethod
      def is_valid_GQTYPE(self,x):
          """Group Quarters Type"""
          if x is None or x == "None":
              return False
          return (leftpad(x,3)==leftpad('106',3)) or (leftpad(x,3)==leftpad('103',3)) or (leftpad(x,3)==leftpad('102',3)) or (leftpad(x,3)==leftpad('104',3)) or (leftpad(x,3)==leftpad('602',3)) or (leftpad(x,3)==leftpad('105',3)) or (leftpad(x,3)==leftpad('301',3)) or (leftpad(x,3)==leftpad('401',3)) or (leftpad(x,3)==leftpad('402',3)) or (leftpad(x,3)==leftpad('403',3)) or (leftpad(x,3)==leftpad('203',3)) or (leftpad(x,3)==leftpad('997',3)) or (leftpad(x,3)==leftpad('501',3)) or (leftpad(x,3)==leftpad('601',3)) or (leftpad(x,3)==leftpad('706',3)) or (leftpad(x,3)==leftpad('801',3)) or (leftpad(x,3)==leftpad('201',3)) or (leftpad(x,3)==leftpad('704',3)) or (leftpad(x,3)==leftpad('701',3)) or (leftpad(x,3)==leftpad('904',3)) or (leftpad(x,3)==leftpad('405',3)) or (leftpad(x,3)==leftpad('802',3)) or (leftpad(x,3)==leftpad('202',3)) or (leftpad(x,3)==leftpad('903',3)) or (leftpad(x,3)==leftpad('900',3)) or (leftpad(x,3)==leftpad('901',3)) or (leftpad(x,3)==leftpad('101',3)) or (leftpad(x,3)==leftpad('000',3)) or (leftpad(x,3)==leftpad('404',3))
      @classmethod
      def is_valid_RELSHIP(self,x):
          """Edited Relationship"""
          if x is None or x == "None":
              return False
          return (leftpad(x,2)==leftpad('25',2)) or (leftpad(x,2)==leftpad('32',2)) or (leftpad(x,2)==leftpad('23',2)) or (leftpad(x,2)==leftpad('20',2)) or (leftpad(x,2)==leftpad('26',2)) or (leftpad(x,2)==leftpad('30',2)) or (leftpad(x,2)==leftpad('34',2)) or (leftpad(x,2)==leftpad('37',2)) or (leftpad(x,2)==leftpad('33',2)) or (leftpad(x,2)==leftpad('36',2)) or (leftpad(x,2)==leftpad('24',2)) or (leftpad(x,2)==leftpad('38',2)) or (leftpad(x,2)==leftpad('21',2)) or (leftpad(x,2)==leftpad('35',2)) or (leftpad(x,2)==leftpad('31',2)) or (leftpad(x,2)==leftpad('22',2)) or (leftpad(x,2)==leftpad('29',2)) or (leftpad(x,2)==leftpad('28',2)) or (leftpad(x,2)==leftpad('27',2))
      @classmethod
      def is_valid_QSEX(self,x):
          """Edited Sex"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('1',1))
      @classmethod
      def is_valid_QAGE(self,x):
          """Edited Age"""
          if x is None or x == "None":
              return False
          x = str(x).strip()
          try:
              x = int(x)
          except ValueError:
              return False
          return (0 <= x <= 115)
      @classmethod
      def is_valid_CENHISP(self,x):
          """Hispanic Origin"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('1',1))
      @classmethod
      def is_valid_CENRACE(self,x):
          """Census Race"""
          if x is None or x == "None":
              return False
          return (leftpad(x,2)==leftpad('14',2)) or (leftpad(x,2)==leftpad('16',2)) or (leftpad(x,2)==leftpad('09',2)) or (leftpad(x,2)==leftpad('11',2)) or (leftpad(x,2)==leftpad('01',2)) or (leftpad(x,2)==leftpad('12',2)) or (leftpad(x,2)==leftpad('20',2)) or (leftpad(x,2)==leftpad('17',2)) or (leftpad(x,2)==leftpad('06',2)) or (leftpad(x,2)==leftpad('15',2)) or (leftpad(x,2)==leftpad('26',2)) or (leftpad(x,2)==leftpad('30',2)) or (leftpad(x,2)==leftpad('36',2)) or (leftpad(x,2)==leftpad('45',2)) or (leftpad(x,2)==leftpad('46',2)) or (leftpad(x,2)==leftpad('55',2)) or (leftpad(x,2)==leftpad('61',2)) or (leftpad(x,2)==leftpad('18',2)) or (leftpad(x,2)==leftpad('27',2)) or (leftpad(x,2)==leftpad('03',2)) or (leftpad(x,2)==leftpad('10',2)) or (leftpad(x,2)==leftpad('13',2)) or (leftpad(x,2)==leftpad('23',2)) or (leftpad(x,2)==leftpad('54',2)) or (leftpad(x,2)==leftpad('07',2)) or (leftpad(x,2)==leftpad('33',2)) or (leftpad(x,2)==leftpad('53',2)) or (leftpad(x,2)==leftpad('22',2)) or (leftpad(x,2)==leftpad('31',2)) or (leftpad(x,2)==leftpad('41',2)) or (leftpad(x,2)==leftpad('48',2)) or (leftpad(x,2)==leftpad('50',2)) or (leftpad(x,2)==leftpad('25',2)) or (leftpad(x,2)==leftpad('28',2)) or (leftpad(x,2)==leftpad('29',2)) or (leftpad(x,2)==leftpad('32',2)) or (leftpad(x,2)==leftpad('34',2)) or (leftpad(x,2)==leftpad('52',2)) or (leftpad(x,2)==leftpad('59',2)) or (leftpad(x,2)==leftpad('02',2)) or (leftpad(x,2)==leftpad('47',2)) or (leftpad(x,2)==leftpad('37',2)) or (leftpad(x,2)==leftpad('19',2)) or (leftpad(x,2)==leftpad('40',2)) or (leftpad(x,2)==leftpad('08',2)) or (leftpad(x,2)==leftpad('21',2)) or (leftpad(x,2)==leftpad('56',2)) or (leftpad(x,2)==leftpad('39',2)) or (leftpad(x,2)==leftpad('38',2)) or (leftpad(x,2)==leftpad('44',2)) or (leftpad(x,2)==leftpad('42',2)) or (leftpad(x,2)==leftpad('49',2)) or (leftpad(x,2)==leftpad('57',2)) or (leftpad(x,2)==leftpad('63',2)) or (leftpad(x,2)==leftpad('51',2)) or (leftpad(x,2)==leftpad('04',2)) or (leftpad(x,2)==leftpad('24',2)) or (leftpad(x,2)==leftpad('58',2)) or (leftpad(x,2)==leftpad('60',2)) or (leftpad(x,2)==leftpad('62',2)) or (leftpad(x,2)==leftpad('35',2)) or (leftpad(x,2)==leftpad('05',2)) or (leftpad(x,2)==leftpad('43',2))
      @classmethod
      def is_valid_LIVE_ALONE(self,x):
          """Person Living Alone"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('1',1))
  
      @classmethod
      def validate_pipe_delimited(self,x):
          fields = x.split('|')
          if len(fields)!=16: return False
          if self.is_valid_SCHEMA_TYPE_CODE(fields[1]) == False: return False
          if self.is_valid_SCHEMA_BUILD_ID(fields[2]) == False: return False
          if self.is_valid_TABBLKST(fields[3]) == False: return False
          if self.is_valid_TABBLKCOU(fields[4]) == False: return False
          if self.is_valid_TABTRACTCE(fields[5]) == False: return False
          if self.is_valid_TABBLKGRPCE(fields[6]) == False: return False
          if self.is_valid_TABBLK(fields[7]) == False: return False
          if self.is_valid_EPNUM(fields[8]) == False: return False
          if self.is_valid_RTYPE(fields[9]) == False: return False
          if self.is_valid_GQTYPE(fields[10]) == False: return False
          if self.is_valid_RELSHIP(fields[11]) == False: return False
          if self.is_valid_QSEX(fields[12]) == False: return False
          if self.is_valid_QAGE(fields[13]) == False: return False
          if self.is_valid_CENHISP(fields[14]) == False: return False
          if self.is_valid_CENRACE(fields[15]) == False: return False
          if self.is_valid_LIVE_ALONE(fields[16]) == False: return False
          return True
  
  class MDF_Person:
      __slots__ = ['SCHEMA_TYPE_CODE', 'SCHEMA_BUILD_ID', 'TABBLKST', 'TABBLKCOU', 'TABTRACTCE', 'TABBLKGRPCE', 'TABBLK', 'EPNUM', 'RTYPE', 'GQTYPE', 'RELSHIP', 'QSEX', 'QAGE', 'CENHISP', 'CENRACE', 'LIVE_ALONE']
      def __repr__(self):
          return 'MDF_Person<SCHEMA_TYPE_CODE:{},SCHEMA_BUILD_ID:{},TABBLKST:{},TABBLKCOU:{},TABTRACTCE:{},TABBLKGRPCE:{},TABBLK:{},EPNUM:{},RTYPE:{},GQTYPE:{},RELSHIP:{},QSEX:{},QAGE:{},CENHISP:{},CENRACE:{},LIVE_ALONE:{}>'.format(self.SCHEMA_TYPE_CODE,self.SCHEMA_BUILD_ID,self.TABBLKST,self.TABBLKCOU,self.TABTRACTCE,self.TABBLKGRPCE,self.TABBLK,self.EPNUM,self.RTYPE,self.GQTYPE,self.RELSHIP,self.QSEX,self.QAGE,self.CENHISP,self.CENRACE,self.LIVE_ALONE)
      def __init__(self,line=None):
          if line:
              if '|' in line:
                  self.parse_pipe_delimited(line)
              else:
                  self.parse_column_specified(line)
      @classmethod
      def name(self):
          return 'MDF_Person'
  
      def parse_pipe_delimited(self,line):
          fields = line.split('|')
          if len(fields)!=16:
              raise ValueError(f'expected 16 fields, found {len(fields)}')
          self.SCHEMA_TYPE_CODE = fields[0]  # Schema Type Code
          self.SCHEMA_BUILD_ID = fields[1]  # Schema Build ID
          self.TABBLKST        = fields[2]  # 2020 Tabulation State (FIPS)
          self.TABBLKCOU       = fields[3]  # 2020 Tabulation County (FIPS)
          self.TABTRACTCE      = fields[4]  # 2020 Tabulation Census Tract
          self.TABBLKGRPCE     = fields[5]  # 2020 Census Block Group
          self.TABBLK          = fields[6]  # 2020 Block Number
          self.EPNUM           = fields[7]  # Privacy Edited Person Number
          self.RTYPE           = fields[8]  # Record Type
          self.GQTYPE          = fields[9]  # Group Quarters Type
          self.RELSHIP         = fields[10]  # Edited Relationship
          self.QSEX            = fields[11]  # Edited Sex
          self.QAGE            = fields[12]  # Edited Age
          self.CENHISP         = fields[13]  # Hispanic Origin
          self.CENRACE         = fields[14]  # Census Race
          self.LIVE_ALONE      = fields[15]  # Person Living Alone
  
      def parse_column_specified(self,line):
          self.SCHEMA_TYPE_CODE = None   # no column information for SCHEMA_TYPE_CODE
          self.SCHEMA_BUILD_ID = None   # no column information for SCHEMA_BUILD_ID
          self.TABBLKST        = None   # no column information for TABBLKST
          self.TABBLKCOU       = None   # no column information for TABBLKCOU
          self.TABTRACTCE      = None   # no column information for TABTRACTCE
          self.TABBLKGRPCE     = None   # no column information for TABBLKGRPCE
          self.TABBLK          = None   # no column information for TABBLK
          self.EPNUM           = None   # no column information for EPNUM
          self.RTYPE           = None   # no column information for RTYPE
          self.GQTYPE          = None   # no column information for GQTYPE
          self.RELSHIP         = None   # no column information for RELSHIP
          self.QSEX            = None   # no column information for QSEX
          self.QAGE            = None   # no column information for QAGE
          self.CENHISP         = None   # no column information for CENHISP
          self.CENRACE         = None   # no column information for CENRACE
          self.LIVE_ALONE      = None   # no column information for LIVE_ALONE
  
      def validate(self):
          """Return True if the object data validates"""
          if not MDF_Person_validator.is_valid_SCHEMA_TYPE_CODE(self.SCHEMA_TYPE_CODE): return False
          if not MDF_Person_validator.is_valid_SCHEMA_BUILD_ID(self.SCHEMA_BUILD_ID): return False
          if not MDF_Person_validator.is_valid_TABBLKST(self.TABBLKST): return False
          if not MDF_Person_validator.is_valid_TABBLKCOU(self.TABBLKCOU): return False
          if not MDF_Person_validator.is_valid_TABTRACTCE(self.TABTRACTCE): return False
          if not MDF_Person_validator.is_valid_TABBLKGRPCE(self.TABBLKGRPCE): return False
          if not MDF_Person_validator.is_valid_TABBLK(self.TABBLK): return False
          if not MDF_Person_validator.is_valid_EPNUM(self.EPNUM): return False
          if not MDF_Person_validator.is_valid_RTYPE(self.RTYPE): return False
          if not MDF_Person_validator.is_valid_GQTYPE(self.GQTYPE): return False
          if not MDF_Person_validator.is_valid_RELSHIP(self.RELSHIP): return False
          if not MDF_Person_validator.is_valid_QSEX(self.QSEX): return False
          if not MDF_Person_validator.is_valid_QAGE(self.QAGE): return False
          if not MDF_Person_validator.is_valid_CENHISP(self.CENHISP): return False
          if not MDF_Person_validator.is_valid_CENRACE(self.CENRACE): return False
          if not MDF_Person_validator.is_valid_LIVE_ALONE(self.LIVE_ALONE): return False
          return True
  
      def validate_reason(self):
          reason=[]
          if not MDF_Person_validator.is_valid_SCHEMA_TYPE_CODE(self.SCHEMA_TYPE_CODE): reason.append('SCHEMA_TYPE_CODE ('+str(self.SCHEMA_TYPE_CODE)+') out of range (MPD-MPD)')
          if not MDF_Person_validator.is_valid_SCHEMA_BUILD_ID(self.SCHEMA_BUILD_ID): reason.append('SCHEMA_BUILD_ID ('+str(self.SCHEMA_BUILD_ID)+') out of range ()')
          if not MDF_Person_validator.is_valid_TABBLKST(self.TABBLKST): reason.append('TABBLKST ('+str(self.TABBLKST)+') out of range (44-51, 72-72, 08-13, 53-56, 01-02, 04-06, 15-42)')
          if not MDF_Person_validator.is_valid_TABBLKCOU(self.TABBLKCOU): reason.append('TABBLKCOU ('+str(self.TABBLKCOU)+') out of range (001-840)')
          if not MDF_Person_validator.is_valid_TABTRACTCE(self.TABTRACTCE): reason.append('TABTRACTCE ('+str(self.TABTRACTCE)+') out of range (000100-998999)')
          if not MDF_Person_validator.is_valid_TABBLKGRPCE(self.TABBLKGRPCE): reason.append('TABBLKGRPCE ('+str(self.TABBLKGRPCE)+') out of range (0-9)')
          if not MDF_Person_validator.is_valid_TABBLK(self.TABBLK): reason.append('TABBLK ('+str(self.TABBLK)+') out of range (0001-9999)')
          if not MDF_Person_validator.is_valid_EPNUM(self.EPNUM): reason.append('EPNUM ('+str(self.EPNUM)+') out of range (0-999999999)')
          if not MDF_Person_validator.is_valid_RTYPE(self.RTYPE): reason.append('RTYPE ('+str(self.RTYPE)+') out of range (5-5, 3-3)')
          if not MDF_Person_validator.is_valid_GQTYPE(self.GQTYPE): reason.append('GQTYPE ('+str(self.GQTYPE)+') out of range (106-106, 103-103, 102-102, 104-104, 602-602, 105-105, 301-301, 401-401, 402-402, 403-403, 203-203, 997-997, 501-501, 601-601, 706-706, 801-801, 201-201, 704-704, 701-701, 904-904, 405-405, 802-802, 202-202, 903-903, 900-900, 901-901, 101-101, 000-000, 404-404)')
          if not MDF_Person_validator.is_valid_RELSHIP(self.RELSHIP): reason.append('RELSHIP ('+str(self.RELSHIP)+') out of range (25-25, 32-32, 23-23, 20-20, 26-26, 30-30, 34-34, 37-37, 33-33, 36-36, 24-24, 38-38, 21-21, 35-35, 31-31, 22-22, 29-29, 28-28, 27-27)')
          if not MDF_Person_validator.is_valid_QSEX(self.QSEX): reason.append('QSEX ('+str(self.QSEX)+') out of range (2-2, 1-1)')
          if not MDF_Person_validator.is_valid_QAGE(self.QAGE): reason.append('QAGE ('+str(self.QAGE)+') out of range (0-115)')
          if not MDF_Person_validator.is_valid_CENHISP(self.CENHISP): reason.append('CENHISP ('+str(self.CENHISP)+') out of range (2-2, 1-1)')
          if not MDF_Person_validator.is_valid_CENRACE(self.CENRACE): reason.append('CENRACE ('+str(self.CENRACE)+') out of range (14-14, 16-16, 09-09, 11-11, 01-01, 12-12, 20-20, 17-17, 06-06, 15-15, 26-26, 30-30, 36-36, 45-45, 46-46, 55-55, 61-61, 18-18, 27-27, 03-03, 10-10, 13-13, 23-23, 54-54, 07-07, 33-33, 53-53, 22-22, 31-31, 41-41, 48-48, 50-50, 25-25, 28-28, 29-29, 32-32, 34-34, 52-52, 59-59, 02-02, 47-47, 37-37, 19-19, 40-40, 08-08, 21-21, 56-56, 39-39, 38-38, 44-44, 42-42, 49-49, 57-57, 63-63, 51-51, 04-04, 24-24, 58-58, 60-60, 62-62, 35-35, 05-05, 43-43)')
          if not MDF_Person_validator.is_valid_LIVE_ALONE(self.LIVE_ALONE): reason.append('LIVE_ALONE ('+str(self.LIVE_ALONE)+') out of range (2-2, 0-0, 1-1)')
          return ', '.join(reason)
  
      def SparkSQLRow(self):
          """Return a SparkSQL Row object for this object."""
          from pyspark.sql import Row
          return Row(
              schema_type_code=safe_str(self.SCHEMA_TYPE_CODE),
              schema_build_id=safe_str(self.SCHEMA_BUILD_ID),
              tabblkst=safe_str(self.TABBLKST),
              tabblkcou=safe_str(self.TABBLKCOU),
              tabtractce=safe_str(self.TABTRACTCE),
              tabblkgrpce=safe_str(self.TABBLKGRPCE),
              tabblk=safe_str(self.TABBLK),
              epnum=safe_int(self.EPNUM),
              rtype=safe_str(self.RTYPE),
              gqtype=safe_str(self.GQTYPE),
              relship=safe_str(self.RELSHIP),
              qsex=safe_str(self.QSEX),
              qage=safe_int(self.QAGE),
              cenhisp=safe_str(self.CENHISP),
              cenrace=safe_str(self.CENRACE),
              live_alone=safe_str(self.LIVE_ALONE),
          )
  
  
      @staticmethod
      def parse_line(line):
          # Read a line and return it as a dictionary.
          inst: MDF_Person = MDF_Person()
          inst.parse_column_specified(line)
          assert inst.validate(), f'A line is invalid!! line: {line}, validate_reason: {inst.validate_reason()}'
          row = inst.SparkSQLRow()
          return row
  
      @staticmethod
      def parse_piped_line(line):
          # Read a pipe-delimited line and return it as a dictionary.
          inst: MDF_Person = MDF_Person()
          inst.parse_pipe_delimited(line)
          assert inst.validate(), f'A line is invalid!! line: {line}, validate_reason: {inst.validate_reason()}'
          row = inst.SparkSQLRow()
          return row
  
  
  
  # Automatically generated on Fri Oct 30 14:46:58 2020 by /mnt/users/will0555/new-das-vm/das-vm-config/das_decennial/das_framework/ctools/schema/table.py
  
  def leftpad(x,width):
      return ' '*(width-len(str(x)))+str(x)
  
  def between(a,b,c,width):
      if len(b) > width:
          return False
      if '.' in a or '.' in b or '.' in c:
          try:
              return float(a) <= float(b) <= float(c)
          except ValueError:
              pass  # tries to return a float but might have weird input like 1.1.0 which will be compared traditionally instead
      b = b.replace(' ', '0')
      return leftpad(a,width) <= leftpad(b,width) <= leftpad(c,width)
  
  
  def safe_int(i):
      try:
          return int(i)
      except (TypeError, ValueError) as e:
          return None
  
  def safe_float(i):
      try:
          return float(i)
      except (TypeError, ValueError) as e:
          return None
  
  def safe_str(i):
      try:
          return str(i)
      except (TypeError, ValueError) as e:
          return None
  
  
  class MDF_Unit_validator:
      @classmethod
      def is_valid_SCHEMA_TYPE_CODE(self,x):
          """Schema Type Code"""
          if x is None or x == "None":
              return False
          return (leftpad(x,3)==leftpad('MUD',3))
      @classmethod
      def is_valid_SCHEMA_BUILD_ID(self,x):
          """Schema Build ID"""
          if x is None or x == "None":
              return False
          return True
      @classmethod
      def is_valid_TABBLKST(self,x):
          """2020 Tabulation State (FIPS)"""
          if x is None or x == "None":
              return False
          return (between('44',x,'51',2)) or (leftpad(x,2)==leftpad('72',2)) or (between('08',x,'13',2)) or (between('53',x,'56',2)) or (between('01',x,'02',2)) or (between('04',x,'06',2)) or (between('15',x,'42',2))
      @classmethod
      def is_valid_TABBLKCOU(self,x):
          """2020 Tabulation County (FIPS)"""
          if x is None or x == "None":
              return False
          return (between('001',x,'840',3))
      @classmethod
      def is_valid_TABTRACTCE(self,x):
          """2020 Tabulation Census Tract"""
          if x is None or x == "None":
              return False
          return (between('000100',x,'998999',6))
      @classmethod
      def is_valid_TABBLKGRPCE(self,x):
          """2020 Census Block Group"""
          if x is None or x == "None":
              return False
          return (between('0',x,'9',1))
      @classmethod
      def is_valid_TABBLK(self,x):
          """2020 Block Number"""
          if x is None or x == "None":
              return False
          return (between('0001',x,'9999',4))
      @classmethod
      def is_valid_RTYPE(self,x):
          """Record Type"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('4',1))
      @classmethod
      def is_valid_GQTYPE(self,x):
          """Group Quarters Type"""
          if x is None or x == "None":
              return False
          return (leftpad(x,3)==leftpad('106',3)) or (leftpad(x,3)==leftpad('103',3)) or (leftpad(x,3)==leftpad('102',3)) or (leftpad(x,3)==leftpad('104',3)) or (leftpad(x,3)==leftpad('602',3)) or (leftpad(x,3)==leftpad('105',3)) or (leftpad(x,3)==leftpad('301',3)) or (leftpad(x,3)==leftpad('401',3)) or (leftpad(x,3)==leftpad('402',3)) or (leftpad(x,3)==leftpad('403',3)) or (leftpad(x,3)==leftpad('203',3)) or (leftpad(x,3)==leftpad('997',3)) or (leftpad(x,3)==leftpad('501',3)) or (leftpad(x,3)==leftpad('601',3)) or (leftpad(x,3)==leftpad('706',3)) or (leftpad(x,3)==leftpad('801',3)) or (leftpad(x,3)==leftpad('201',3)) or (leftpad(x,3)==leftpad('704',3)) or (leftpad(x,3)==leftpad('701',3)) or (leftpad(x,3)==leftpad('904',3)) or (leftpad(x,3)==leftpad('405',3)) or (leftpad(x,3)==leftpad('802',3)) or (leftpad(x,3)==leftpad('202',3)) or (leftpad(x,3)==leftpad('903',3)) or (leftpad(x,3)==leftpad('900',3)) or (leftpad(x,3)==leftpad('901',3)) or (leftpad(x,3)==leftpad('101',3)) or (leftpad(x,3)==leftpad('000',3)) or (leftpad(x,3)==leftpad('404',3))
      @classmethod
      def is_valid_TEN(self,x):
          """Tenure"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('1',1)) or (leftpad(x,1)==leftpad('3',1)) or (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('4',1))
      @classmethod
      def is_valid_VACS(self,x):
          """Vacancy Status"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('7',1)) or (leftpad(x,1)==leftpad('1',1)) or (leftpad(x,1)==leftpad('5',1)) or (leftpad(x,1)==leftpad('3',1)) or (leftpad(x,1)==leftpad('6',1)) or (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('4',1))
      @classmethod
      def is_valid_HHSIZE(self,x):
          """Population Count"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('7',1)) or (leftpad(x,1)==leftpad('1',1)) or (leftpad(x,1)==leftpad('5',1)) or (leftpad(x,1)==leftpad('3',1)) or (leftpad(x,1)==leftpad('6',1)) or (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('4',1))
      @classmethod
      def is_valid_HHT(self,x):
          """Household/Family Type"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('7',1)) or (leftpad(x,1)==leftpad('1',1)) or (leftpad(x,1)==leftpad('5',1)) or (leftpad(x,1)==leftpad('3',1)) or (leftpad(x,1)==leftpad('6',1)) or (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('4',1))
      @classmethod
      def is_valid_HHT2(self,x):
          """Household/Family Type (Includes Cohabiting)"""
          if x is None or x == "None":
              return False
          return (leftpad(x,2)==leftpad('02',2)) or (leftpad(x,2)==leftpad('03',2)) or (leftpad(x,2)==leftpad('09',2)) or (leftpad(x,2)==leftpad('01',2)) or (leftpad(x,2)==leftpad('00',2)) or (leftpad(x,2)==leftpad('10',2)) or (leftpad(x,2)==leftpad('11',2)) or (leftpad(x,2)==leftpad('06',2)) or (leftpad(x,2)==leftpad('07',2)) or (leftpad(x,2)==leftpad('04',2)) or (leftpad(x,2)==leftpad('12',2)) or (leftpad(x,2)==leftpad('08',2)) or (leftpad(x,2)==leftpad('05',2))
      @classmethod
      def is_valid_CPLT(self,x):
          """Couple Type"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('1',1)) or (leftpad(x,1)==leftpad('5',1)) or (leftpad(x,1)==leftpad('3',1)) or (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('4',1))
      @classmethod
      def is_valid_UPART(self,x):
          """Presence and Type of Unmarried Partner Household"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('1',1)) or (leftpad(x,1)==leftpad('5',1)) or (leftpad(x,1)==leftpad('3',1)) or (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('4',1))
      @classmethod
      def is_valid_MULTG(self,x):
          """Multigenerational Household"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('1',1))
      @classmethod
      def is_valid_THHLDRAGE(self,x):
          """Age of Householder"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('7',1)) or (leftpad(x,1)==leftpad('1',1)) or (leftpad(x,1)==leftpad('5',1)) or (leftpad(x,1)==leftpad('3',1)) or (leftpad(x,1)==leftpad('6',1)) or (leftpad(x,1)==leftpad('8',1)) or (leftpad(x,1)==leftpad('9',1)) or (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('4',1))
      @classmethod
      def is_valid_THHSPAN(self,x):
          """Hispanic Householder"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('1',1))
      @classmethod
      def is_valid_THHRACE(self,x):
          """Race of Householder"""
          if x is None or x == "None":
              return False
          return (leftpad(x,2)==leftpad('02',2)) or (leftpad(x,2)==leftpad('03',2)) or (leftpad(x,2)==leftpad('01',2)) or (leftpad(x,2)==leftpad('00',2)) or (leftpad(x,2)==leftpad('06',2)) or (leftpad(x,2)==leftpad('07',2)) or (leftpad(x,2)==leftpad('04',2)) or (leftpad(x,2)==leftpad('05',2))
      @classmethod
      def is_valid_PAOC(self,x):
          """Presence and Age of Own Children Under 18"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('1',1)) or (leftpad(x,1)==leftpad('3',1)) or (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('4',1))
      @classmethod
      def is_valid_TP18(self,x):
          """Presence of People Under 18 Years in Household"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('1',1))
      @classmethod
      def is_valid_TP60(self,x):
          """Presence of People 60 Years and Over in Household"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('1',1))
      @classmethod
      def is_valid_TP65(self,x):
          """Presence of People 65 Years and Over in Household"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('1',1))
      @classmethod
      def is_valid_TP75(self,x):
          """Presence of People 75 Years and Over in Household"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('1',1))
      @classmethod
      def is_valid_PAC(self,x):
          """Presence and Age of Children Under 18"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('1',1)) or (leftpad(x,1)==leftpad('3',1)) or (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('4',1))
      @classmethod
      def is_valid_HHSEX(self,x):
          """Sex of Householder"""
          if x is None or x == "None":
              return False
          return (leftpad(x,1)==leftpad('2',1)) or (leftpad(x,1)==leftpad('0',1)) or (leftpad(x,1)==leftpad('1',1))
  
      @classmethod
      def validate_pipe_delimited(self,x):
          fields = x.split('|')
          if len(fields)!=27: return False
          if self.is_valid_SCHEMA_TYPE_CODE(fields[1]) == False: return False
          if self.is_valid_SCHEMA_BUILD_ID(fields[2]) == False: return False
          if self.is_valid_TABBLKST(fields[3]) == False: return False
          if self.is_valid_TABBLKCOU(fields[4]) == False: return False
          if self.is_valid_TABTRACTCE(fields[5]) == False: return False
          if self.is_valid_TABBLKGRPCE(fields[6]) == False: return False
          if self.is_valid_TABBLK(fields[7]) == False: return False
          if self.is_valid_RTYPE(fields[8]) == False: return False
          if self.is_valid_GQTYPE(fields[9]) == False: return False
          if self.is_valid_TEN(fields[10]) == False: return False
          if self.is_valid_VACS(fields[11]) == False: return False
          if self.is_valid_HHSIZE(fields[12]) == False: return False
          if self.is_valid_HHT(fields[13]) == False: return False
          if self.is_valid_HHT2(fields[14]) == False: return False
          if self.is_valid_CPLT(fields[15]) == False: return False
          if self.is_valid_UPART(fields[16]) == False: return False
          if self.is_valid_MULTG(fields[17]) == False: return False
          if self.is_valid_THHLDRAGE(fields[18]) == False: return False
          if self.is_valid_THHSPAN(fields[19]) == False: return False
          if self.is_valid_THHRACE(fields[20]) == False: return False
          if self.is_valid_PAOC(fields[21]) == False: return False
          if self.is_valid_TP18(fields[22]) == False: return False
          if self.is_valid_TP60(fields[23]) == False: return False
          if self.is_valid_TP65(fields[24]) == False: return False
          if self.is_valid_TP75(fields[25]) == False: return False
          if self.is_valid_PAC(fields[26]) == False: return False
          if self.is_valid_HHSEX(fields[27]) == False: return False
          return True
  
  class MDF_Unit:
      __slots__ = ['SCHEMA_TYPE_CODE', 'SCHEMA_BUILD_ID', 'TABBLKST', 'TABBLKCOU', 'TABTRACTCE', 'TABBLKGRPCE', 'TABBLK', 'RTYPE', 'GQTYPE', 'TEN', 'VACS', 'HHSIZE', 'HHT', 'HHT2', 'CPLT', 'UPART', 'MULTG', 'THHLDRAGE', 'THHSPAN', 'THHRACE', 'PAOC', 'TP18', 'TP60', 'TP65', 'TP75', 'PAC', 'HHSEX']
      def __repr__(self):
          return 'MDF_Unit<SCHEMA_TYPE_CODE:{},SCHEMA_BUILD_ID:{},TABBLKST:{},TABBLKCOU:{},TABTRACTCE:{},TABBLKGRPCE:{},TABBLK:{},RTYPE:{},GQTYPE:{},TEN:{},VACS:{},HHSIZE:{},HHT:{},HHT2:{},CPLT:{},UPART:{},MULTG:{},THHLDRAGE:{},THHSPAN:{},THHRACE:{},PAOC:{},TP18:{},TP60:{},TP65:{},TP75:{},PAC:{},HHSEX:{}>'.format(self.SCHEMA_TYPE_CODE,self.SCHEMA_BUILD_ID,self.TABBLKST,self.TABBLKCOU,self.TABTRACTCE,self.TABBLKGRPCE,self.TABBLK,self.RTYPE,self.GQTYPE,self.TEN,self.VACS,self.HHSIZE,self.HHT,self.HHT2,self.CPLT,self.UPART,self.MULTG,self.THHLDRAGE,self.THHSPAN,self.THHRACE,self.PAOC,self.TP18,self.TP60,self.TP65,self.TP75,self.PAC,self.HHSEX)
      def __init__(self,line=None):
          if line:
              if '|' in line:
                  self.parse_pipe_delimited(line)
              else:
                  self.parse_column_specified(line)
      @classmethod
      def name(self):
          return 'MDF_Unit'
  
      def parse_pipe_delimited(self,line):
          fields = line.split('|')
          if len(fields)!=27:
              raise ValueError(f'expected 27 fields, found {len(fields)}')
          self.SCHEMA_TYPE_CODE = fields[0]  # Schema Type Code
          self.SCHEMA_BUILD_ID = fields[1]  # Schema Build ID
          self.TABBLKST        = fields[2]  # 2020 Tabulation State (FIPS)
          self.TABBLKCOU       = fields[3]  # 2020 Tabulation County (FIPS)
          self.TABTRACTCE      = fields[4]  # 2020 Tabulation Census Tract
          self.TABBLKGRPCE     = fields[5]  # 2020 Census Block Group
          self.TABBLK          = fields[6]  # 2020 Block Number
          self.RTYPE           = fields[7]  # Record Type
          self.GQTYPE          = fields[8]  # Group Quarters Type
          self.TEN             = fields[9]  # Tenure
          self.VACS            = fields[10]  # Vacancy Status
          self.HHSIZE          = fields[11]  # Population Count
          self.HHT             = fields[12]  # Household/Family Type
          self.HHT2            = fields[13]  # Household/Family Type (Includes Cohabiting)
          self.CPLT            = fields[14]  # Couple Type
          self.UPART           = fields[15]  # Presence and Type of Unmarried Partner Household
          self.MULTG           = fields[16]  # Multigenerational Household
          self.THHLDRAGE       = fields[17]  # Age of Householder
          self.THHSPAN         = fields[18]  # Hispanic Householder
          self.THHRACE         = fields[19]  # Race of Householder
          self.PAOC            = fields[20]  # Presence and Age of Own Children Under 18
          self.TP18            = fields[21]  # Presence of People Under 18 Years in Household
          self.TP60            = fields[22]  # Presence of People 60 Years and Over in Household
          self.TP65            = fields[23]  # Presence of People 65 Years and Over in Household
          self.TP75            = fields[24]  # Presence of People 75 Years and Over in Household
          self.PAC             = fields[25]  # Presence and Age of Children Under 18
          self.HHSEX           = fields[26]  # Sex of Householder
  
      def parse_column_specified(self,line):
          self.SCHEMA_TYPE_CODE = None   # no column information for SCHEMA_TYPE_CODE
          self.SCHEMA_BUILD_ID = None   # no column information for SCHEMA_BUILD_ID
          self.TABBLKST        = None   # no column information for TABBLKST
          self.TABBLKCOU       = None   # no column information for TABBLKCOU
          self.TABTRACTCE      = None   # no column information for TABTRACTCE
          self.TABBLKGRPCE     = None   # no column information for TABBLKGRPCE
          self.TABBLK          = None   # no column information for TABBLK
          self.RTYPE           = None   # no column information for RTYPE
          self.GQTYPE          = None   # no column information for GQTYPE
          self.TEN             = None   # no column information for TEN
          self.VACS            = None   # no column information for VACS
          self.HHSIZE          = None   # no column information for HHSIZE
          self.HHT             = None   # no column information for HHT
          self.HHT2            = None   # no column information for HHT2
          self.CPLT            = None   # no column information for CPLT
          self.UPART           = None   # no column information for UPART
          self.MULTG           = None   # no column information for MULTG
          self.THHLDRAGE       = None   # no column information for THHLDRAGE
          self.THHSPAN         = None   # no column information for THHSPAN
          self.THHRACE         = None   # no column information for THHRACE
          self.PAOC            = None   # no column information for PAOC
          self.TP18            = None   # no column information for TP18
          self.TP60            = None   # no column information for TP60
          self.TP65            = None   # no column information for TP65
          self.TP75            = None   # no column information for TP75
          self.PAC             = None   # no column information for PAC
          self.HHSEX           = None   # no column information for HHSEX
  
      def validate(self):
          """Return True if the object data validates"""
          if not MDF_Unit_validator.is_valid_SCHEMA_TYPE_CODE(self.SCHEMA_TYPE_CODE): return False
          if not MDF_Unit_validator.is_valid_SCHEMA_BUILD_ID(self.SCHEMA_BUILD_ID): return False
          if not MDF_Unit_validator.is_valid_TABBLKST(self.TABBLKST): return False
          if not MDF_Unit_validator.is_valid_TABBLKCOU(self.TABBLKCOU): return False
          if not MDF_Unit_validator.is_valid_TABTRACTCE(self.TABTRACTCE): return False
          if not MDF_Unit_validator.is_valid_TABBLKGRPCE(self.TABBLKGRPCE): return False
          if not MDF_Unit_validator.is_valid_TABBLK(self.TABBLK): return False
          if not MDF_Unit_validator.is_valid_RTYPE(self.RTYPE): return False
          if not MDF_Unit_validator.is_valid_GQTYPE(self.GQTYPE): return False
          if not MDF_Unit_validator.is_valid_TEN(self.TEN): return False
          if not MDF_Unit_validator.is_valid_VACS(self.VACS): return False
          if not MDF_Unit_validator.is_valid_HHSIZE(self.HHSIZE): return False
          if not MDF_Unit_validator.is_valid_HHT(self.HHT): return False
          if not MDF_Unit_validator.is_valid_HHT2(self.HHT2): return False
          if not MDF_Unit_validator.is_valid_CPLT(self.CPLT): return False
          if not MDF_Unit_validator.is_valid_UPART(self.UPART): return False
          if not MDF_Unit_validator.is_valid_MULTG(self.MULTG): return False
          if not MDF_Unit_validator.is_valid_THHLDRAGE(self.THHLDRAGE): return False
          if not MDF_Unit_validator.is_valid_THHSPAN(self.THHSPAN): return False
          if not MDF_Unit_validator.is_valid_THHRACE(self.THHRACE): return False
          if not MDF_Unit_validator.is_valid_PAOC(self.PAOC): return False
          if not MDF_Unit_validator.is_valid_TP18(self.TP18): return False
          if not MDF_Unit_validator.is_valid_TP60(self.TP60): return False
          if not MDF_Unit_validator.is_valid_TP65(self.TP65): return False
          if not MDF_Unit_validator.is_valid_TP75(self.TP75): return False
          if not MDF_Unit_validator.is_valid_PAC(self.PAC): return False
          if not MDF_Unit_validator.is_valid_HHSEX(self.HHSEX): return False
          return True
  
      def validate_reason(self):
          reason=[]
          if not MDF_Unit_validator.is_valid_SCHEMA_TYPE_CODE(self.SCHEMA_TYPE_CODE): reason.append('SCHEMA_TYPE_CODE ('+str(self.SCHEMA_TYPE_CODE)+') out of range (MUD-MUD)')
          if not MDF_Unit_validator.is_valid_SCHEMA_BUILD_ID(self.SCHEMA_BUILD_ID): reason.append('SCHEMA_BUILD_ID ('+str(self.SCHEMA_BUILD_ID)+') out of range ()')
          if not MDF_Unit_validator.is_valid_TABBLKST(self.TABBLKST): reason.append('TABBLKST ('+str(self.TABBLKST)+') out of range (44-51, 72-72, 08-13, 53-56, 01-02, 04-06, 15-42)')
          if not MDF_Unit_validator.is_valid_TABBLKCOU(self.TABBLKCOU): reason.append('TABBLKCOU ('+str(self.TABBLKCOU)+') out of range (001-840)')
          if not MDF_Unit_validator.is_valid_TABTRACTCE(self.TABTRACTCE): reason.append('TABTRACTCE ('+str(self.TABTRACTCE)+') out of range (000100-998999)')
          if not MDF_Unit_validator.is_valid_TABBLKGRPCE(self.TABBLKGRPCE): reason.append('TABBLKGRPCE ('+str(self.TABBLKGRPCE)+') out of range (0-9)')
          if not MDF_Unit_validator.is_valid_TABBLK(self.TABBLK): reason.append('TABBLK ('+str(self.TABBLK)+') out of range (0001-9999)')
          if not MDF_Unit_validator.is_valid_RTYPE(self.RTYPE): reason.append('RTYPE ('+str(self.RTYPE)+') out of range (2-2, 4-4)')
          if not MDF_Unit_validator.is_valid_GQTYPE(self.GQTYPE): reason.append('GQTYPE ('+str(self.GQTYPE)+') out of range (106-106, 103-103, 102-102, 104-104, 602-602, 105-105, 301-301, 401-401, 402-402, 403-403, 203-203, 997-997, 501-501, 601-601, 706-706, 801-801, 201-201, 704-704, 701-701, 904-904, 405-405, 802-802, 202-202, 903-903, 900-900, 901-901, 101-101, 000-000, 404-404)')
          if not MDF_Unit_validator.is_valid_TEN(self.TEN): reason.append('TEN ('+str(self.TEN)+') out of range (1-1, 3-3, 2-2, 0-0, 4-4)')
          if not MDF_Unit_validator.is_valid_VACS(self.VACS): reason.append('VACS ('+str(self.VACS)+') out of range (7-7, 1-1, 5-5, 3-3, 6-6, 2-2, 0-0, 4-4)')
          if not MDF_Unit_validator.is_valid_HHSIZE(self.HHSIZE): reason.append('HHSIZE ('+str(self.HHSIZE)+') out of range (7-7, 1-1, 5-5, 3-3, 6-6, 2-2, 0-0, 4-4)')
          if not MDF_Unit_validator.is_valid_HHT(self.HHT): reason.append('HHT ('+str(self.HHT)+') out of range (7-7, 1-1, 5-5, 3-3, 6-6, 2-2, 0-0, 4-4)')
          if not MDF_Unit_validator.is_valid_HHT2(self.HHT2): reason.append('HHT2 ('+str(self.HHT2)+') out of range (02-02, 03-03, 09-09, 01-01, 00-00, 10-10, 11-11, 06-06, 07-07, 04-04, 12-12, 08-08, 05-05)')
          if not MDF_Unit_validator.is_valid_CPLT(self.CPLT): reason.append('CPLT ('+str(self.CPLT)+') out of range (1-1, 5-5, 3-3, 2-2, 0-0, 4-4)')
          if not MDF_Unit_validator.is_valid_UPART(self.UPART): reason.append('UPART ('+str(self.UPART)+') out of range (1-1, 5-5, 3-3, 2-2, 0-0, 4-4)')
          if not MDF_Unit_validator.is_valid_MULTG(self.MULTG): reason.append('MULTG ('+str(self.MULTG)+') out of range (2-2, 0-0, 1-1)')
          if not MDF_Unit_validator.is_valid_THHLDRAGE(self.THHLDRAGE): reason.append('THHLDRAGE ('+str(self.THHLDRAGE)+') out of range (7-7, 1-1, 5-5, 3-3, 6-6, 8-8, 9-9, 2-2, 0-0, 4-4)')
          if not MDF_Unit_validator.is_valid_THHSPAN(self.THHSPAN): reason.append('THHSPAN ('+str(self.THHSPAN)+') out of range (2-2, 0-0, 1-1)')
          if not MDF_Unit_validator.is_valid_THHRACE(self.THHRACE): reason.append('THHRACE ('+str(self.THHRACE)+') out of range (02-02, 03-03, 01-01, 00-00, 06-06, 07-07, 04-04, 05-05)')
          if not MDF_Unit_validator.is_valid_PAOC(self.PAOC): reason.append('PAOC ('+str(self.PAOC)+') out of range (1-1, 3-3, 2-2, 0-0, 4-4)')
          if not MDF_Unit_validator.is_valid_TP18(self.TP18): reason.append('TP18 ('+str(self.TP18)+') out of range (0-0, 1-1)')
          if not MDF_Unit_validator.is_valid_TP60(self.TP60): reason.append('TP60 ('+str(self.TP60)+') out of range (0-0, 1-1)')
          if not MDF_Unit_validator.is_valid_TP65(self.TP65): reason.append('TP65 ('+str(self.TP65)+') out of range (0-0, 1-1)')
          if not MDF_Unit_validator.is_valid_TP75(self.TP75): reason.append('TP75 ('+str(self.TP75)+') out of range (0-0, 1-1)')
          if not MDF_Unit_validator.is_valid_PAC(self.PAC): reason.append('PAC ('+str(self.PAC)+') out of range (1-1, 3-3, 2-2, 0-0, 4-4)')
          if not MDF_Unit_validator.is_valid_HHSEX(self.HHSEX): reason.append('HHSEX ('+str(self.HHSEX)+') out of range (2-2, 0-0, 1-1)')
          return ', '.join(reason)
  
      def SparkSQLRow(self):
          """Return a SparkSQL Row object for this object."""
          from pyspark.sql import Row
          return Row(
              schema_type_code=safe_str(self.SCHEMA_TYPE_CODE),
              schema_build_id=safe_str(self.SCHEMA_BUILD_ID),
              tabblkst=safe_str(self.TABBLKST),
              tabblkcou=safe_str(self.TABBLKCOU),
              tabtractce=safe_str(self.TABTRACTCE),
              tabblkgrpce=safe_str(self.TABBLKGRPCE),
              tabblk=safe_str(self.TABBLK),
              rtype=safe_str(self.RTYPE),
              gqtype=safe_str(self.GQTYPE),
              ten=safe_str(self.TEN),
              vacs=safe_str(self.VACS),
              hhsize=safe_str(self.HHSIZE),
              hht=safe_str(self.HHT),
              hht2=safe_str(self.HHT2),
              cplt=safe_str(self.CPLT),
              upart=safe_str(self.UPART),
              multg=safe_str(self.MULTG),
              thhldrage=safe_str(self.THHLDRAGE),
              thhspan=safe_str(self.THHSPAN),
              thhrace=safe_str(self.THHRACE),
              paoc=safe_str(self.PAOC),
              tp18=safe_str(self.TP18),
              tp60=safe_str(self.TP60),
              tp65=safe_str(self.TP65),
              tp75=safe_str(self.TP75),
              pac=safe_str(self.PAC),
              hhsex=safe_str(self.HHSEX),
          )
  
  
      @staticmethod
      def parse_line(line):
          # Read a line and return it as a dictionary.
          inst: MDF_Unit = MDF_Unit()
          inst.parse_column_specified(line)
          assert inst.validate(), f'A line is invalid!! line: {line}, validate_reason: {inst.validate_reason()}'
          row = inst.SparkSQLRow()
          return row
  
      @staticmethod
      def parse_piped_line(line):
          # Read a pipe-delimited line and return it as a dictionary.
          inst: MDF_Unit = MDF_Unit()
          inst.parse_pipe_delimited(line)
          assert inst.validate(), f'A line is invalid!! line: {line}, validate_reason: {inst.validate_reason()}'
          row = inst.SparkSQLRow()
          return row
  
  
  
  SPEC_CLASS_OBJECTS = [MDF_Person(),MDF_Unit()]
  null = None
  SPEC_DICT = {"tables": {"MDF_Person": {"name": "MDF_Person", "variables": [{"name": "SCHEMA_TYPE_CODE", "vtype": "CHAR", "position": "1", "desc": "Schema Type Code", "column": null, "width": 3, "ranges": [{"a": "MPD", "b": "MPD"}]}, {"name": "SCHEMA_BUILD_ID", "vtype": "CHAR", "position": "2", "desc": "Schema Build ID", "column": null, "width": 5, "ranges": []}, {"name": "TABBLKST", "vtype": "CHAR", "position": "3", "desc": "2020 Tabulation State (FIPS)", "column": null, "width": 2, "ranges": [{"a": "44", "b": "51"}, {"a": "72", "b": "72"}, {"a": "08", "b": "13"}, {"a": "53", "b": "56"}, {"a": "01", "b": "02"}, {"a": "04", "b": "06"}, {"a": "15", "b": "42"}]}, {"name": "TABBLKCOU", "vtype": "CHAR", "position": "4", "desc": "2020 Tabulation County (FIPS)", "column": null, "width": 3, "ranges": [{"a": "001", "b": "840"}]}, {"name": "TABTRACTCE", "vtype": "CHAR", "position": "5", "desc": "2020 Tabulation Census Tract", "column": null, "width": 6, "ranges": [{"a": "000100", "b": "998999"}]}, {"name": "TABBLKGRPCE", "vtype": "CHAR", "position": "6", "desc": "2020 Census Block Group", "column": null, "width": 1, "ranges": [{"a": "0", "b": "9"}]}, {"name": "TABBLK", "vtype": "CHAR", "position": "7", "desc": "2020 Block Number", "column": null, "width": 4, "ranges": [{"a": "0001", "b": "9999"}]}, {"name": "EPNUM", "vtype": "INT", "position": "8", "desc": "Privacy Edited Person Number", "column": null, "width": 9, "ranges": [{"a": "0", "b": "999999999"}]}, {"name": "RTYPE", "vtype": "CHAR", "position": "9", "desc": "Record Type", "column": null, "width": 1, "ranges": [{"a": "5", "b": "5"}, {"a": "3", "b": "3"}]}, {"name": "GQTYPE", "vtype": "CHAR", "position": "10", "desc": "Group Quarters Type", "column": null, "width": 3, "ranges": [{"a": "106", "b": "106"}, {"a": "103", "b": "103"}, {"a": "102", "b": "102"}, {"a": "104", "b": "104"}, {"a": "602", "b": "602"}, {"a": "105", "b": "105"}, {"a": "301", "b": "301"}, {"a": "401", "b": "401"}, {"a": "402", "b": "402"}, {"a": "403", "b": "403"}, {"a": "203", "b": "203"}, {"a": "997", "b": "997"}, {"a": "501", "b": "501"}, {"a": "601", "b": "601"}, {"a": "706", "b": "706"}, {"a": "801", "b": "801"}, {"a": "201", "b": "201"}, {"a": "704", "b": "704"}, {"a": "701", "b": "701"}, {"a": "904", "b": "904"}, {"a": "405", "b": "405"}, {"a": "802", "b": "802"}, {"a": "202", "b": "202"}, {"a": "903", "b": "903"}, {"a": "900", "b": "900"}, {"a": "901", "b": "901"}, {"a": "101", "b": "101"}, {"a": "000", "b": "000"}, {"a": "404", "b": "404"}]}, {"name": "RELSHIP", "vtype": "CHAR", "position": "11", "desc": "Edited Relationship", "column": null, "width": 2, "ranges": [{"a": "25", "b": "25"}, {"a": "32", "b": "32"}, {"a": "23", "b": "23"}, {"a": "20", "b": "20"}, {"a": "26", "b": "26"}, {"a": "30", "b": "30"}, {"a": "34", "b": "34"}, {"a": "37", "b": "37"}, {"a": "33", "b": "33"}, {"a": "36", "b": "36"}, {"a": "24", "b": "24"}, {"a": "38", "b": "38"}, {"a": "21", "b": "21"}, {"a": "35", "b": "35"}, {"a": "31", "b": "31"}, {"a": "22", "b": "22"}, {"a": "29", "b": "29"}, {"a": "28", "b": "28"}, {"a": "27", "b": "27"}]}, {"name": "QSEX", "vtype": "CHAR", "position": "12", "desc": "Edited Sex", "column": null, "width": 1, "ranges": [{"a": "2", "b": "2"}, {"a": "1", "b": "1"}]}, {"name": "QAGE", "vtype": "INT", "position": "13", "desc": "Edited Age", "column": null, "width": 3, "ranges": [{"a": "0", "b": "115"}]}, {"name": "CENHISP", "vtype": "CHAR", "position": "14", "desc": "Hispanic Origin", "column": null, "width": 1, "ranges": [{"a": "2", "b": "2"}, {"a": "1", "b": "1"}]}, {"name": "CENRACE", "vtype": "CHAR", "position": "15", "desc": "Census Race", "column": null, "width": 2, "ranges": [{"a": "14", "b": "14"}, {"a": "16", "b": "16"}, {"a": "09", "b": "09"}, {"a": "11", "b": "11"}, {"a": "01", "b": "01"}, {"a": "12", "b": "12"}, {"a": "20", "b": "20"}, {"a": "17", "b": "17"}, {"a": "06", "b": "06"}, {"a": "15", "b": "15"}, {"a": "26", "b": "26"}, {"a": "30", "b": "30"}, {"a": "36", "b": "36"}, {"a": "45", "b": "45"}, {"a": "46", "b": "46"}, {"a": "55", "b": "55"}, {"a": "61", "b": "61"}, {"a": "18", "b": "18"}, {"a": "27", "b": "27"}, {"a": "03", "b": "03"}, {"a": "10", "b": "10"}, {"a": "13", "b": "13"}, {"a": "23", "b": "23"}, {"a": "54", "b": "54"}, {"a": "07", "b": "07"}, {"a": "33", "b": "33"}, {"a": "53", "b": "53"}, {"a": "22", "b": "22"}, {"a": "31", "b": "31"}, {"a": "41", "b": "41"}, {"a": "48", "b": "48"}, {"a": "50", "b": "50"}, {"a": "25", "b": "25"}, {"a": "28", "b": "28"}, {"a": "29", "b": "29"}, {"a": "32", "b": "32"}, {"a": "34", "b": "34"}, {"a": "52", "b": "52"}, {"a": "59", "b": "59"}, {"a": "02", "b": "02"}, {"a": "47", "b": "47"}, {"a": "37", "b": "37"}, {"a": "19", "b": "19"}, {"a": "40", "b": "40"}, {"a": "08", "b": "08"}, {"a": "21", "b": "21"}, {"a": "56", "b": "56"}, {"a": "39", "b": "39"}, {"a": "38", "b": "38"}, {"a": "44", "b": "44"}, {"a": "42", "b": "42"}, {"a": "49", "b": "49"}, {"a": "57", "b": "57"}, {"a": "63", "b": "63"}, {"a": "51", "b": "51"}, {"a": "04", "b": "04"}, {"a": "24", "b": "24"}, {"a": "58", "b": "58"}, {"a": "60", "b": "60"}, {"a": "62", "b": "62"}, {"a": "35", "b": "35"}, {"a": "05", "b": "05"}, {"a": "43", "b": "43"}]}, {"name": "LIVE_ALONE", "vtype": "CHAR", "position": "16", "desc": "Person Living Alone", "column": null, "width": 1, "ranges": [{"a": "2", "b": "2"}, {"a": "0", "b": "0"}, {"a": "1", "b": "1"}]}]}, "MDF_Unit": {"name": "MDF_Unit", "variables": [{"name": "SCHEMA_TYPE_CODE", "vtype": "CHAR", "position": "1", "desc": "Schema Type Code", "column": null, "width": 3, "ranges": [{"a": "MUD", "b": "MUD"}]}, {"name": "SCHEMA_BUILD_ID", "vtype": "CHAR", "position": "2", "desc": "Schema Build ID", "column": null, "width": 5, "ranges": []}, {"name": "TABBLKST", "vtype": "CHAR", "position": "3", "desc": "2020 Tabulation State (FIPS)", "column": null, "width": 2, "ranges": [{"a": "44", "b": "51"}, {"a": "72", "b": "72"}, {"a": "08", "b": "13"}, {"a": "53", "b": "56"}, {"a": "01", "b": "02"}, {"a": "04", "b": "06"}, {"a": "15", "b": "42"}]}, {"name": "TABBLKCOU", "vtype": "CHAR", "position": "4", "desc": "2020 Tabulation County (FIPS)", "column": null, "width": 3, "ranges": [{"a": "001", "b": "840"}]}, {"name": "TABTRACTCE", "vtype": "CHAR", "position": "5", "desc": "2020 Tabulation Census Tract", "column": null, "width": 6, "ranges": [{"a": "000100", "b": "998999"}]}, {"name": "TABBLKGRPCE", "vtype": "CHAR", "position": "6", "desc": "2020 Census Block Group", "column": null, "width": 1, "ranges": [{"a": "0", "b": "9"}]}, {"name": "TABBLK", "vtype": "CHAR", "position": "7", "desc": "2020 Block Number", "column": null, "width": 4, "ranges": [{"a": "0001", "b": "9999"}]}, {"name": "RTYPE", "vtype": "CHAR", "position": "8", "desc": "Record Type", "column": null, "width": 1, "ranges": [{"a": "2", "b": "2"}, {"a": "4", "b": "4"}]}, {"name": "GQTYPE", "vtype": "CHAR", "position": "9", "desc": "Group Quarters Type", "column": null, "width": 3, "ranges": [{"a": "106", "b": "106"}, {"a": "103", "b": "103"}, {"a": "102", "b": "102"}, {"a": "104", "b": "104"}, {"a": "602", "b": "602"}, {"a": "105", "b": "105"}, {"a": "301", "b": "301"}, {"a": "401", "b": "401"}, {"a": "402", "b": "402"}, {"a": "403", "b": "403"}, {"a": "203", "b": "203"}, {"a": "997", "b": "997"}, {"a": "501", "b": "501"}, {"a": "601", "b": "601"}, {"a": "706", "b": "706"}, {"a": "801", "b": "801"}, {"a": "201", "b": "201"}, {"a": "704", "b": "704"}, {"a": "701", "b": "701"}, {"a": "904", "b": "904"}, {"a": "405", "b": "405"}, {"a": "802", "b": "802"}, {"a": "202", "b": "202"}, {"a": "903", "b": "903"}, {"a": "900", "b": "900"}, {"a": "901", "b": "901"}, {"a": "101", "b": "101"}, {"a": "000", "b": "000"}, {"a": "404", "b": "404"}]}, {"name": "TEN", "vtype": "CHAR", "position": "10", "desc": "Tenure", "column": null, "width": 1, "ranges": [{"a": "1", "b": "1"}, {"a": "3", "b": "3"}, {"a": "2", "b": "2"}, {"a": "0", "b": "0"}, {"a": "4", "b": "4"}]}, {"name": "VACS", "vtype": "CHAR", "position": "11", "desc": "Vacancy Status", "column": null, "width": 1, "ranges": [{"a": "7", "b": "7"}, {"a": "1", "b": "1"}, {"a": "5", "b": "5"}, {"a": "3", "b": "3"}, {"a": "6", "b": "6"}, {"a": "2", "b": "2"}, {"a": "0", "b": "0"}, {"a": "4", "b": "4"}]}, {"name": "HHSIZE", "vtype": "CHAR", "position": "12", "desc": "Population Count", "column": null, "width": 1, "ranges": [{"a": "7", "b": "7"}, {"a": "1", "b": "1"}, {"a": "5", "b": "5"}, {"a": "3", "b": "3"}, {"a": "6", "b": "6"}, {"a": "2", "b": "2"}, {"a": "0", "b": "0"}, {"a": "4", "b": "4"}]}, {"name": "HHT", "vtype": "CHAR", "position": "13", "desc": "Household/Family Type", "column": null, "width": 1, "ranges": [{"a": "7", "b": "7"}, {"a": "1", "b": "1"}, {"a": "5", "b": "5"}, {"a": "3", "b": "3"}, {"a": "6", "b": "6"}, {"a": "2", "b": "2"}, {"a": "0", "b": "0"}, {"a": "4", "b": "4"}]}, {"name": "HHT2", "vtype": "CHAR", "position": "14", "desc": "Household/Family Type (Includes Cohabiting)", "column": null, "width": 2, "ranges": [{"a": "02", "b": "02"}, {"a": "03", "b": "03"}, {"a": "09", "b": "09"}, {"a": "01", "b": "01"}, {"a": "00", "b": "00"}, {"a": "10", "b": "10"}, {"a": "11", "b": "11"}, {"a": "06", "b": "06"}, {"a": "07", "b": "07"}, {"a": "04", "b": "04"}, {"a": "12", "b": "12"}, {"a": "08", "b": "08"}, {"a": "05", "b": "05"}]}, {"name": "CPLT", "vtype": "CHAR", "position": "15", "desc": "Couple Type", "column": null, "width": 1, "ranges": [{"a": "1", "b": "1"}, {"a": "5", "b": "5"}, {"a": "3", "b": "3"}, {"a": "2", "b": "2"}, {"a": "0", "b": "0"}, {"a": "4", "b": "4"}]}, {"name": "UPART", "vtype": "CHAR", "position": "16", "desc": "Presence and Type of Unmarried Partner Household", "column": null, "width": 1, "ranges": [{"a": "1", "b": "1"}, {"a": "5", "b": "5"}, {"a": "3", "b": "3"}, {"a": "2", "b": "2"}, {"a": "0", "b": "0"}, {"a": "4", "b": "4"}]}, {"name": "MULTG", "vtype": "CHAR", "position": "17", "desc": "Multigenerational Household", "column": null, "width": 1, "ranges": [{"a": "2", "b": "2"}, {"a": "0", "b": "0"}, {"a": "1", "b": "1"}]}, {"name": "THHLDRAGE", "vtype": "CHAR", "position": "18", "desc": "Age of Householder", "column": null, "width": 1, "ranges": [{"a": "7", "b": "7"}, {"a": "1", "b": "1"}, {"a": "5", "b": "5"}, {"a": "3", "b": "3"}, {"a": "6", "b": "6"}, {"a": "8", "b": "8"}, {"a": "9", "b": "9"}, {"a": "2", "b": "2"}, {"a": "0", "b": "0"}, {"a": "4", "b": "4"}]}, {"name": "THHSPAN", "vtype": "CHAR", "position": "19", "desc": "Hispanic Householder", "column": null, "width": 1, "ranges": [{"a": "2", "b": "2"}, {"a": "0", "b": "0"}, {"a": "1", "b": "1"}]}, {"name": "THHRACE", "vtype": "CHAR", "position": "20", "desc": "Race of Householder", "column": null, "width": 2, "ranges": [{"a": "02", "b": "02"}, {"a": "03", "b": "03"}, {"a": "01", "b": "01"}, {"a": "00", "b": "00"}, {"a": "06", "b": "06"}, {"a": "07", "b": "07"}, {"a": "04", "b": "04"}, {"a": "05", "b": "05"}]}, {"name": "PAOC", "vtype": "CHAR", "position": "21", "desc": "Presence and Age of Own Children Under 18", "column": null, "width": 1, "ranges": [{"a": "1", "b": "1"}, {"a": "3", "b": "3"}, {"a": "2", "b": "2"}, {"a": "0", "b": "0"}, {"a": "4", "b": "4"}]}, {"name": "TP18", "vtype": "CHAR", "position": "22", "desc": "Presence of People Under 18 Years in Household", "column": null, "width": 1, "ranges": [{"a": "0", "b": "0"}, {"a": "1", "b": "1"}]}, {"name": "TP60", "vtype": "CHAR", "position": "23", "desc": "Presence of People 60 Years and Over in Household", "column": null, "width": 1, "ranges": [{"a": "0", "b": "0"}, {"a": "1", "b": "1"}]}, {"name": "TP65", "vtype": "CHAR", "position": "24", "desc": "Presence of People 65 Years and Over in Household", "column": null, "width": 1, "ranges": [{"a": "0", "b": "0"}, {"a": "1", "b": "1"}]}, {"name": "TP75", "vtype": "CHAR", "position": "25", "desc": "Presence of People 75 Years and Over in Household", "column": null, "width": 1, "ranges": [{"a": "0", "b": "0"}, {"a": "1", "b": "1"}]}, {"name": "PAC", "vtype": "CHAR", "position": "26", "desc": "Presence and Age of Children Under 18", "column": null, "width": 1, "ranges": [{"a": "1", "b": "1"}, {"a": "3", "b": "3"}, {"a": "2", "b": "2"}, {"a": "0", "b": "0"}, {"a": "4", "b": "4"}]}, {"name": "HHSEX", "vtype": "CHAR", "position": "27", "desc": "Sex of Householder", "column": null, "width": 1, "ranges": [{"a": "2", "b": "2"}, {"a": "0", "b": "0"}, {"a": "1", "b": "1"}]}]}}}
  