Source code for countrydata.interface

# -*- coding: utf-8 -*-

"""Countrydata main interface module."""

import os
import json

from countrydata.data.consts import COUNTRYDATA_FILES_DIRECTORY
from countrydata.data.spec import (
    disambiguate_field_name,
    get_spec_field_by_value,
    get_valid_field_names,
    spec,
)

[docs]class Country: """Represents a country and exposes his data. Their initialization is very flexible, allowing to construct it using any field of the data that refers to a country. This possibilities that any data field can be used as reference and this class acts as a country data factory. Can be initialized explicitly by optional arguments (safer) or implicitly, delegating to the library the inference process of discover what field of the data you are using. Implicitly, the class can be initalized defining a country value of any type of data as first positional argument. For example, let's try to initialize the United States using ISO-3361-1 Alpha2 codes implicitly: >>> country = Country("US") >>> country.a3 'USA' >>> country.num 840 Explicitly, the class can be initialized using one of the supported `field names <https://countrydata.readthedocs.io/en/latest/data/overview.html#supported-fields>`_. This way is faster and safer. United States can be initialized by his ISO-3361-1 Numeric3 number: >>> country = Country(num=840) >>> country.a3 'USA' """ def __init__(self, *args, **kwargs): self.data = None self._properties = None if len(args) > 0: if len(args) > 1: msg = "You must pass only one country initializator value" raise ValueError(msg) spec_field = get_spec_field_by_value(args[0]) if spec_field is None: raise ValueError("%s value not found in data" % args[0]) # Get the country file path searching by field path # and initialize the interface by filepath self.__init_by_filepath__( spec_field.filepath(args[0])) else: if len(kwargs) > 0: if len(kwargs) > 1: raise ValueError( "You must pass only one country initializator value") # Dissambiguate field name _field_name = list(kwargs.keys())[0] field_name = disambiguate_field_name(_field_name) # If is not a valid field name if field_name is None: valid_field_names = get_valid_field_names() valid_field_names_msg = "" for valid_field_name in valid_field_names: valid_field_names_msg += " - %s\n" % valid_field_name msg_schema = "You must pass a valid field to initialize" \ + " %s interface. Valid field names:\n%s" msg = msg_schema % (self.__class.__name__, valid_field_names_msg) raise ValueError(msg) # Get value field_value = kwargs[_field_name] # Check by what field we must initialize the interface for spec_field in spec: if field_name in spec_field.ids: # Get the country file path searching by field path # and initialize the interface by filepath self.__init_by_filepath__( spec_field.filepath(field_value)) break else: msg = "You must pass a country initializator value." raise ValueError(msg) def __init_by_filepath__(self, filepath): with open(filepath, "r") as f: self.data = json.loads(f.read(), parse_int=int) def __getattr__(self, attr): return self._get_data_properties()[attr] def __dir__(self): return super().__dir__() + list(self._get_data_properties().keys()) def _get_data_properties(self): if self._properties is not None: return self._properties self._properties = {} # For each specification field for spec_field in spec: property_id = spec_field.ids[0] # Traverse 'field_path' keys to access the data _keys = spec_field.field_path.split(":")[1].split(".") value = None _first_temp_value = True for k in _keys: if _first_temp_value: value = self.data[k] self._properties[k] = value _first_temp_value = False else: value = value[k] self._properties[property_id] = value return self._properties
class CountryName: """Represent a localized country name. :param locale: Locale for the country name: :type locale: str :param official: Official name. :type official: str :param short: Short name. :type short: str :param alt: Alternative names. :type alt: list :param regex: Regex that match with all names used for this country. :type regex: str """ def __init__(self, locale="en", official=None, short=None, alt=[], regex=None): self.locale = locale self.official = official self.short = short self.alt = alt self.regex = regex