# Module `Gnumed.business.gmGender`

GNUmed gender handling.

## Functions

`def create_gender_def(tag: str = None, name: str = None, comment: str = None, symbol: str = None)`
  Expand source code

      def create_gender_def(tag:str=None, name:str=None, comment:str=None, symbol:str=None):
              args = {
                      'tag': tag,
                      'name': name,
                      'cmt': comment,
                      'sym': symbol
              }
              SQL = """
                      INSERT INTO dem.gender_label (tag, label, comment, symbol) VALUES (
                              gm.nullify_empty_string(%(tag)s),
                              gm.nullify_empty_string(%(name)s),
                              gm.nullify_empty_string(%(cmt)s),
                              gm.nullify_empty_string(%(sym)s)
                      )
                      RETURNING pk
              """
              rows = gmPG2.run_rw_query(sql = SQL, args = args, return_data = True)
              invalidate_genders_cache()
              return cGenderDef(aPK_obj = rows[0]['pk'])

`def delete_gender_def(pk_gender_label=None)`
  Expand source code

      def delete_gender_def(pk_gender_label=None):
              args = {'pk': pk_gender_label}
              SQL = 'DELETE FROM dem.gender_label WHERE pk = %(pk)s'
              gmPG2.run_rw_query(sql = SQL, args = args)
              invalidate_genders_cache()
              return True

`def get_genders(as_instance: bool = False, order_by: str = None) ‑> list`
  Expand source code

      def get_genders(as_instance:bool=False, order_by:str=None) -> list:
              """Retrieves the list of known genders from the database."""
              global __LIST__gender_defs
              if not __LIST__gender_defs:
                      SQL = _SQL_get_gender_defs
                      if order_by:
                              SQL += ' ORDER BY %s' % order_by
                      __LIST__gender_defs = gmPG2.run_ro_query(sql = SQL)
                      _log.debug('gender definitions in database: %s' % __LIST__gender_defs)
              if not as_instance:
                      return __LIST__gender_defs

              return [ cGenderDef(row = {'data': r, 'pk_field': 'pk_gender_label'}) for r in __LIST__gender_defs ]

  Retrieves the list of known genders from the database.

`def invalidate_genders_cache()`
  Expand source code

      def invalidate_genders_cache():
              global __LIST__gender_defs
              __LIST__gender_defs = None

`def map_firstnames2gender(firstnames=None)`
  Expand source code

      def map_firstnames2gender(firstnames=None):
              """Try getting the gender for the given first name."""

              if firstnames is None:
                      return None

              SQL = 'SELECT gender FROM dem.name_gender_map WHERE name ILIKE %(fn)s LIMIT 1'
              args = {'fn': firstnames}
              rows = gmPG2.run_ro_query(sql = SQL, args = args)
              if not rows:
                      return None

              return rows[0][0]

  Try getting the gender for the given first name.

`def map_gender2salutation(gender=None)`
  Expand source code

      def map_gender2salutation(gender=None):
              """Maps GNUmed related i18n-aware gender specifiers to a human-readable salutation."""
              global __MAP__gender2salutation
              if not __MAP__gender2salutation:
                      __MAP__gender2salutation = {
                              'm': _('Mr'),
                              'f': _('Mrs'),
                              'tf': '',
                              'tm': '',
                              'h': '',
                              None: ''
                      }
                      _log.debug('gender -> salutation mapping: %s' % __MAP__gender2salutation)
              try:
                      return __MAP__gender2salutation[gender]

              except KeyError:
                      return ''

  Maps GNUmed related i18n-aware gender specifiers to a human-readable salutation.

`def map_gender2string(gender: str = None) ‑> str`
  Expand source code

      def map_gender2string(gender:str=None) -> str:
              """Maps GNUmed related i18n-aware gender specifiers to a human-readable string."""
              genders = get_genders()
              global __MAP__gender2string
              if not __MAP__gender2string:
                      __MAP__gender2string = {
                              'm': _('male'),
                              'f': _('female'),
                              'tf': '',
                              'tm': '',
                              'h': '',
                              None: _('unknown gender')
                      }
                      for g in genders:
                              if g['l10n_name']:
                                      __MAP__gender2string[g['l10n_tag']] = g['l10n_name']
                                      __MAP__gender2string[g['tag']] = g['l10n_name']
                      _log.debug('gender -> string mapping: %s' % __MAP__gender2string)
              try:
                      return __MAP__gender2string[gender]

              except KeyError:
                      return '?%s?' % gender

  Maps GNUmed related i18n-aware gender specifiers to a human-readable string.

`def map_gender2symbol(gender: str = None) ‑> str`
  Expand source code

      def map_gender2symbol(gender:str=None) -> str:
              """Maps GNUmed related i18n-aware gender specifiers to a unicode symbol."""
              genders = get_genders()
              global __MAP__gender2symbol
              if not __MAP__gender2symbol:
                      # built-in defaults
                      __MAP__gender2symbol = {
                              'm': '\u2642',
                              'f': '\u2640',
                              'tf': '\u26A5\u2640',
                              #'tf': u'\u2642\u2640-\u2640',
                              'tm': '\u26A5\u2642',
                              #'tm': u'\u2642\u2640-\u2642',
                              'h': '\u26A5',
                              #'h': u'\u2642\u2640',
                              None: '?\u26A5?'
                      }
                      # update from database, possibly adding more genders
                      for g in genders:
                              if g['l10n_symbol']:
                                      __MAP__gender2symbol[g['l10n_tag']] = g['l10n_symbol']
                                      __MAP__gender2symbol[g['tag']] = g['l10n_symbol']
                      _log.debug('gender -> symbol mapping: %s' % __MAP__gender2symbol)
              try:
                      return __MAP__gender2symbol[gender]

              except KeyError:
                      return '?%s?' % gender

  Maps GNUmed related i18n-aware gender specifiers to a unicode symbol.

`def map_gender2tag(gender: str = None) ‑> str`
  Expand source code

      def map_gender2tag(gender:str=None) -> str:
              for gdef in get_genders():
                      if gender in [gdef['tag'], gdef['l10n_tag'], gdef['name'], gdef['l10n_name'], gdef['symbol'], gdef['l10n_symbol']]:
                              return gdef['tag']

              return None

## Classes

`class cGenderDef (aPK_obj: int | dict = None, row: dict = None, link_obj=None)`
  Expand source code

      class cGenderDef(gmBusinessDBObject.cBusinessDBObject):
              """Represents a gender definition."""

              _cmd_fetch_payload = '%s WHERE pk_gender_label = %%s' % _SQL_get_gender_defs
              _cmds_store_payload = [
                      """UPDATE dem.gender_label SET
                                      tag = gm.nullify_empty_string(%(tag)s),
                                      label = gm.nullify_empty_string(%(name)s),
                                      symbol = gm.nullify_empty_string(%(symbol)s),
                                      comment = gm.nullify_empty_string(%(comment)s)
                              WHERE
                                      pk = %(pk_gender_label)s
                                              AND
                                      xmin = %(xmin_gender_label)s
                              RETURNING
                                      xmin AS xmin_gender_label,
                                      _(tag) as l10n_tag,
                                      _(label) as l10n_name,
                                      _(symbol) as l10n_symbol
                      """
              ]
              _updatable_fields = [
                      'tag',
                      'name',
                      'symbol',
                      'comment'
              ]
              #--------------------------------------------------------
              def format(self):
                      symbol = map_gender2symbol(gender = self._payload['tag'])
                      line = '%(l10n_tag)s: %(l10n_name)s' % self._payload
                      if symbol:
                              line += ' (%s)' % symbol
                      return line

              #--------------------------------------------------------
              def store_field_translation(self, original:str, translation:str, link_obj=None):
                      gmPG2.update_translation_in_database (
                              language = None,        # use current DB language
                              original = original,
                              translation = translation,
                              link_obj = link_obj
                      )
                      invalidate_genders_cache()
                      self.refetch_payload(link_obj = link_obj)

              #--------------------------------------------------------
              def save_payload(self, conn:gmPG2.dbapi.extras.DictConnection=None) -> tuple[bool, tuple]:
                      result = super().save_payload(conn = conn)
                      invalidate_genders_cache()
                      return result

              #--------------------------------------------------------
              def _get_is_in_use(self):
                      SQL = 'SELECT EXISTS (SELECT 1 FROM dem.identity WHERE dem.identity.gender = %(tag)s)'
                      args = {'tag': self._payload['tag']}
                      rows = gmPG2.run_ro_query(sql = SQL, args = args)
                      return rows[0][0]

              is_in_use = property(_get_is_in_use)

  Represents a gender definition.

  Call init from child classes like so:

          super().__init__(aPK_obj = aPK_obj, row = row, link_obj = link_obj)

  ## Args

  `aPK_obj`
    retrieve data from backend
  - an scalar value the ._cmd_fetch_payload WHERE condition must be a simple column: "… WHERE pk_col = %s"
  - a dictionary of values the ._cmd_fetch_payload WHERE condition must consume the dictionary and produce a unique row
  `row`
    must hold the fields
  - data: list of column values for the row selected by ._cmd_fetch_payload (as returned by cursor.fetchone() in the DB-API)
  - pk_field: the name of the primary key column OR
  - pk_obj: a dictionary suitable for being passed to cursor.execute and holding the primary key values, used for composite PKs
  - for example:

        row = {
                'data': rows[0],
                'pk_field': 'pk_XXX (the PK column name)',
                'pk_obj': {'pk_col1': pk_col1_val, 'pk_col2': pk_col2_val}
        }

        rows = gmPG2.run_ro_queries(queries = [{'sql': cmd, 'args': args}])
        objects = [ cChildClass(row = {'data': r, 'pk_field': 'the PK column name'}) for r in rows ]

  ### Ancestors

  - cBusinessDBObject

  ### Instance variables

  `prop is_in_use`
    Expand source code

        def _get_is_in_use(self):
                SQL = 'SELECT EXISTS (SELECT 1 FROM dem.identity WHERE dem.identity.gender = %(tag)s)'
                args = {'tag': self._payload['tag']}
                rows = gmPG2.run_ro_query(sql = SQL, args = args)
                return rows[0][0]

  ### Methods

  `def store_field_translation(self, original: str, translation: str, link_obj=None)`
    Expand source code

        def store_field_translation(self, original:str, translation:str, link_obj=None):
                gmPG2.update_translation_in_database (
                        language = None,        # use current DB language
                        original = original,
                        translation = translation,
                        link_obj = link_obj
                )
                invalidate_genders_cache()
                self.refetch_payload(link_obj = link_obj)

  ### Inherited members

  - `cBusinessDBObject`:
    - `fields_as_dict`
    - `format`
    - `get_fields`
    - `get_patient`
    - `get_updatable_fields`
    - `is_modified`
    - `keys`
    - `patient_pk`
    - `refetch_payload`
    - `same_payload`
    - `save`
    - `save_payload`
    - `staff_id`