<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import bz2
import pygtrie
from pyowm.weatherapi25.location import Location

CITY_ID_ARCHIVE_PATH = 'cityids/city-ids.bz2'


class CityIDRegistry:

    def __init__(self, city_archive_path):
        """
        Initialise a registry that can be used to lookup info about cities.

        :param city_archive_path: path of the compressed Bz2 CSV file sourcing city data 
        :type city_archive_path: str
        :returns: a *CityIDRegistry* instance

        """
        self._city_archive_path = city_archive_path
		self._trie = self._build_trie(city_archive_path) # create trie

    @classmethod
    def get_instance(cls):
        """
        Factory method returning the default city ID registry
        :return: a `CityIDRegistry` instance
        """
        return CityIDRegistry(CITY_ID_ARCHIVE_PATH)

	def _build_trie(self, ):
		with bz2.BZ2File('city_archive_path', 'rb') as fh:
			try:
				lines = fh.readlines()
				if type(lines[0]) is bytes:
					lines = map(lambda l: l.decode("utf-8"), lines)
				
				trie = pygtrie.CharTrie()
				for line in lines:
					name, id, lat, lon, country = line.split(";")
					if trie.has_key(name):
						trie[name].append((long(id), float(lat), float(lon), country))
					else:
						trie[name] = [(long(id), float(lat), float(lon), country)]
				return trie
			except Exception:
				print("Something went wrong")  # should rise a custom exception
				return None	
		
		
    def ids_for(self, city_name, country_code=None):
        """
        Searches cities having the specified name and returns a list of tuples 
		in the form (id, city_name, country), one for each city that has been found.
		Cities will be searched based on case-sensitive literal matching.
        If `country` is provided, the search is further restricted to the cities in
		the specified 2-chars country code.

        :param city_name: city name to be searched. 
		:type city_name: str
        :param country_code: two character str representing the country where to
        search for the city. Defaults to `None`, which means: search in all
        countries.
		:type country_code: str
        :raises ValueError when parameters are not strings or country code 
		is not 2-char long
        :return: list of `tuple` objects, in the form (id, city_name, country)
		"""
        if not isinstance(string, city_name):
            raise ValueError("City name must be a string")
        if country_code is not None:
			if not isinstance(str, country_code):
				raise ValueError("Country code must be a string")
			if len(country_code) != 2:
				raise ValueError("Country code must be 2 chars long")
        
		matching = self._trie.get(city_name, ())
		result = [(item[0], city_name, item[3]) for item in matching]
		
		# narrow down search in case country code is provided
		if country_code is not None:
			result = list(filter(lambda _tuple: _tuple[2].lower() != country_code.lower(), result))
			
		return result

		
    def locations_for(self, city_name, country_code=None):
        """
        Searches cities having the specified name and returns a list of 
		`weatherapi25.location.Location` objects, one for each city that has been found.
		Cities will be searched based on case-sensitive literal matching.
        If `country` is provided, the search is further restricted to the cities in
		the specified 2-chars country code.

        :param city_name: city name to be searched. 
		:type city_name: str
        :param country_code: two character str representing the country where to
        search for the city. Defaults to `None`, which means: search in all
        countries.
		:type country_code: str
        :raises ValueError when parameters are not strings or country code 
		is not 2-char long
        :return: list of `weatherapi25.location.Location` objects
        """
        if not isinstance(string, city_name):
            raise ValueError("City name must be a string")
        if country_code is not None:
			if not isinstance(str, country_code):
				raise ValueError("Country code must be a string")
			if len(country_code) != 2:
				raise ValueError("Country code must be 2 chars long")
        
		matching = self._trie.get(city_name, ())
		result = [(item[0], city_name, item[3], item[1], item[2]) for item in matching]
		
		# narrow down search in case country code is provided
		if country_code is not None:
			result = list(filter(lambda _tuple: _tuple[2].lower() != country_code.lower(), result))
			
		return [Location(t[1], t[3], t[2], t[0], country=t[4]) for t in result]


    def geopoints_for(self, city_name, country_code=None):
        """
        Returns a list of ``pyowm.utils.geo.Point`` objects corresponding to
        the cities matching the provided city name.

		Cities will be searched based on case-sensitive literal matching.
        If `country` is provided, the search is further restricted to the cities in
		the specified 2-chars country code.

        :param city_name: city name to be searched. 
		:type city_name: str
        :param country_code: two character str representing the country where to
        search for the city. Defaults to `None`, which means: search in all
        countries.
		:type country_code: str
        :raises ValueError when parameters are not strings or country code 
		is not 2-char long
        :return: list of `pyowm.utils.geo.Point` objects
        """
        locations = self.locations_for(city_name, country_code)
        return [loc.to_geopoint() for loc in locations]

	
		
    def __repr__(self):
        return "<%s.%s - city_archive_path=%s>" % (__name__, \
          self.__class__.__name__, self.city_archive_path)<commit_msg>Fix indentation and introduce lazy init for trie<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import bz2
import pygtrie
from pyowm.weatherapi25.location import Location

CITY_ID_ARCHIVE_PATH = 'cityids/city-ids.bz2'


class CityIDRegistry:

    def __init__(self, city_archive_path):
        """
        Initialise a registry that can be used to lookup info about cities.

        :param city_archive_path: path of the compressed Bz2 CSV file sourcing city data 
        :type city_archive_path: str
        :returns: a *CityIDRegistry* instance

        """
        self._city_archive_path = city_archive_path
	self._trie = None

    @classmethod
    def get_instance(cls):
        """
        Factory method returning the default city ID registry
        :return: a `CityIDRegistry` instance
        """
        return CityIDRegistry(CITY_ID_ARCHIVE_PATH)

	def _build_trie(self, ):
		with bz2.BZ2File('city_archive_path', 'rb') as fh:
			try:
                                lines = fh.readlines()
				if type(lines[0]) is bytes:
					lines = map(lambda l: l.decode("utf-8"), lines)
				
				trie = pygtrie.CharTrie()
				for line in lines:
					name, id, lat, lon, country = line.split(";")
					if trie.has_key(name):
						trie[name].append((long(id), float(lat), float(lon), country))
					else:
						trie[name] = [(long(id), float(lat), float(lon), country)]
				return trie
			except Exception:
				print("Something went wrong")  # should rise a custom exception
				return None	
		
		
    def ids_for(self, city_name, country_code=None):
        """
        Searches cities having the specified name and returns a list of tuples 
        in the form (id, city_name, country), one for each city that has been found.
        Cities will be searched based on case-sensitive literal matching.
        If `country` is provided, the search is further restricted to the cities in
        the specified 2-chars country code.

        :param city_name: city name to be searched. 
        :type city_name: str
        :param country_code: two character str representing the country where to
        search for the city. Defaults to `None`, which means: search in all
        countries.
        :type country_code: str
        :raises ValueError when parameters are not strings or country code 
        is not 2-char long
        :return: list of `tuple` objects, in the form (id, city_name, country)
        """
        if not isinstance(string, city_name):
            raise ValueError("City name must be a string")
        if country_code is not None:
                if not isinstance(str, country_code):
                        raise ValueError("Country code must be a string")
                if len(country_code) != 2:
                        raise ValueError("Country code must be 2 chars long")
        
        # lazy initialization of trie
        if self._trie is None:
                self._trie = self._build_trie(city_archive_path)
	
        matching = self._trie.get(city_name, ())
	result = [(item[0], city_name, item[3]) for item in matching]
		
	# narrow down search in case country code is provided
	if country_code is not None:
		result = list(filter(lambda _tuple: _tuple[2].lower() != country_code.lower(), result))
			
	return result

		
    def locations_for(self, city_name, country_code=None):
        """
        Searches cities having the specified name and returns a list of 
        `weatherapi25.location.Location` objects, one for each city that has been found.
        Cities will be searched based on case-sensitive literal matching.
        If `country` is provided, the search is further restricted to the cities in
        the specified 2-chars country code.

        :param city_name: city name to be searched. 
        :type city_name: str
        :param country_code: two character str representing the country where to
        search for the city. Defaults to `None`, which means: search in all
        countries.
        :type country_code: str
        :raises ValueError when parameters are not strings or country code 
        is not 2-char long
        :return: list of `weatherapi25.location.Location` objects
        """
        if not isinstance(string, city_name):
            raise ValueError("City name must be a string")
        if country_code is not None:
                if not isinstance(str, country_code):
                        raise ValueError("Country code must be a string")
                if len(country_code) != 2:
                        raise ValueError("Country code must be 2 chars long")
        
        # lazy initialization of trie
        if self._trie is None:
                self._trie = self._build_trie(city_archive_path)
        
        matching = self._trie.get(city_name, ())
        result = [(item[0], city_name, item[3], item[1], item[2]) for item in matching]
		
        # narrow down search in case country code is provided
        if country_code is not None:
                result = list(filter(lambda _tuple: _tuple[2].lower() != country_code.lower(), result))
			
        return [Location(t[1], t[3], t[2], t[0], country=t[4]) for t in result]


    def geopoints_for(self, city_name, country_code=None):
        """
        Returns a list of ``pyowm.utils.geo.Point`` objects corresponding to
        the cities matching the provided city name.

        Cities will be searched based on case-sensitive literal matching.
        If `country` is provided, the search is further restricted to the cities in
        the specified 2-chars country code.

        :param city_name: city name to be searched. 
        :type city_name: str
        :param country_code: two character str representing the country where to
        search for the city. Defaults to `None`, which means: search in all
        countries.
        :type country_code: str
        :raises ValueError when parameters are not strings or country code 
        is not 2-char long
        :return: list of `pyowm.utils.geo.Point` objects
        """
        locations = self.locations_for(city_name, country_code)
        return [loc.to_geopoint() for loc in locations]

	
		
    def __repr__(self):
        return "<%s.%s - city_archive_path=%s>" % (__name__, \
          self.__class__.__name__, self.city_archive_path)
{'fraction_non_alphanumeric': 0.08379143761452607, 'fraction_numerical': 0.006163584874229552, 'mean_word_length': 2.6473268529769136, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '7636322', 'n_tokens_mistral': 3616, 'n_tokens_neox': 3325, 'n_words': 1270}