Repository: joke2k/faker

Issue:
Generation of Country Phone Code
I would like to generate random country phone prefix from here: https://en.wikipedia.org/wiki/List_of_country_calling_codes 
Result should be: +213, +350, +56 etc. 

Is there a way to do this? 
Thanks

Discussion:

Patch:
diff --git a/faker/providers/address/pt_BR/__init__.py b/faker/providers/address/pt_BR/__init__.py
index dacd633f..8b524801 100644
--- a/faker/providers/address/pt_BR/__init__.py
+++ b/faker/providers/address/pt_BR/__init__.py
@@ -99,7 +99,8 @@ class Provider(AddressProvider):
 
     building_number_formats = ('%', '%#', '%#', '%#', '%##')
 
-    postcode_formats = ('########', '#####-###')
+    postcode_raw_formats = ('########', )
+    postcode_all_formats = postcode_raw_formats + ('#####-###', )
 
     bairros = (
         'Aarão Reis', 'Acaba Mundo', 'Acaiaca', 'Ademar Maldonado', 'Aeroporto', 'Aguas Claras', 'Alípio De Melo',
@@ -296,6 +297,16 @@ class Provider(AddressProvider):
         """
         return self.random_element(self.bairros)
 
+    def postcode(self, formatted=True):
+        """
+        Randomly returns a postcode.
+        :param formatted: True to allow formatted postcodes, else False (default True)
+        :example formatted: '41224-212' '83992-291' '12324322'
+        :example raw: '43920231' '34239530'
+        """
+        template = self.postcode_all_formats if formatted else self.postcode_raw_formats
+        return self.bothify(self.random_element(template))
+
     # aliases
     def neighborhood(self):
         return self.bairro()
diff --git a/faker/providers/phone_number/__init__.py b/faker/providers/phone_number/__init__.py
index e333e757..6e812435 100644
--- a/faker/providers/phone_number/__init__.py
+++ b/faker/providers/phone_number/__init__.py
@@ -1,9 +1,59 @@
 from .. import BaseProvider
 
+# Data source
+#
+# The country codes in this provider comes from the following source:
+# List of country calling codes
+# https://en.wikipedia.org/wiki/List_of_country_calling_codes
+#
+# Data was collected from the alphabetical listing by country or region
+
 localized = True
 
 
 class Provider(BaseProvider):
+
+    country_calling_codes = (
+        '+93', '+358 18', '+355', '+213', '+1 684', '+376', '+244', '+1 264',
+        '+1 268', '+54', '+374', '+297', '+247', '+61', '+672 1', '+672', '+43',
+        '+994', '+1 242', '+973', '+880', '+1 246', '+1 268', '+375', '+32',
+        '+501', '+229', '+1 441', '+975', '+591', '+599 7', '+387', '+267',
+        '+55', '+246', '+1 284', '+673', '+359', '+226', '+257', '+855', '+237',
+        '+1', '+238', '+599 3', '+599 4', '+599 7', '+1 345', '+236', '+235',
+        '+64', '+56', '+86', '+61 89164', '+61 89162', '+57', '+269', '+242',
+        '+243', '+682', '+506', '+385', '+53', '+599 9', '+357', '+420',
+        '+45', '+246', '+253', '+1 767', '+1 809', '+1 829', '+1 849', '+670',
+        '+56', '+593', '+20', '+503', '+881 2', '+881 3', '+882 13', '+240',
+        '+291', '+372', '+268', '+251', '+500', '+298', '+679', '+358',
+        '+33', '+596', '+594', '+689', '+241', '+220', '+995', '+49',
+        '+233', '+350', '+881', '+881 8', '+881 9', '+30', '+299', '+1 473',
+        '+590', '+1 671', '+502', '+44 1481', '+44 7781', '+44 7839', '+44 7911', '+224',
+        '+245', '+592', '+509', '+504', '+852', '+36', '+354', '+881 0',
+        '+881 1', '+91', '+62', '+870', '+800', '+882', '+883', '+979',
+        '+808', '+98', '+964', '+353', '+881 6', '+881 7', '+44 1624', '+44 7524',
+        '+44 7624', '+44 7924', '+972', '+39', '+225', '+1 876', '+47 79', '+81',
+        '+44 1534', '+962', '+7 6', '+7 7', '+254', '+686', '+850', '+82',
+        '+383', '+965', '+996', '+856', '+371', '+961', '+266', '+231',
+        '+218', '+423', '+370', '+352', '+853', '+261', '+265', '+60',
+        '+960', '+223', '+356', '+692', '+596', '+222', '+230', '+262 269',
+        '+262 639', '+52', '+691', '+1 808', '+373', '+377', '+976', '+382',
+        '+1 664', '+212', '+258', '+95', '+374 47', '+374 97', '+264', '+674',
+        '+977', '+31', '+1 869', '+687', '+64', '+505', '+227', '+234',
+        '+683', '+672 3', '+389', '+90 392', '+44 28', '+1 670', '+47', '+968',
+        '+92', '+680', '+970', '+507', '+675', '+595', '+51', '+63',
+        '+64', '+48', '+351', '+1 787', '+1 939', '+974', '+262', '+40',
+        '+7', '+250', '+599 4', '+590', '+290', '+1 869', '+1 758', '+590',
+        '+508', '+1 784', '+685', '+378', '+239', '+966', '+221', '+381',
+        '+248', '+232', '+65', '+599 3', '+1 721', '+421', '+386', '+677',
+        '+252', '+27', '+500', '+995 34', '+211', '+34', '+94', '+249',
+        '+597', '+47 79', '+46', '+41', '+963', '+886', '+992', '+255',
+        '+888', '+66', '+882 16', '+228', '+690', '+676', '+373 2', '+373 5',
+        '+1 868', '+290 8', '+216', '+90', '+993', '+1 649', '+688', '+256',
+        '+380', '+971', '+44', '+1', '+878', '+598', '+1 340', '+998',
+        '+678', '+39 06 698', '+379', '+58', '+84', '+1 808', '+681', '+967',
+        '+260', '+255 24', '+263',
+    )
+
     formats = ('###-###-###',)
 
     msisdn_formats = (
@@ -13,6 +63,9 @@ class Provider(BaseProvider):
     def phone_number(self):
         return self.numerify(self.random_element(self.formats))
 
+    def country_calling_code(self):
+        return self.random_element(self.country_calling_codes)
+
     def msisdn(self):
         """ https://en.wikipedia.org/wiki/MSISDN """
         return self.numerify(self.random_element(self.msisdn_formats))


Test patch:
diff --git a/tests/providers/test_address.py b/tests/providers/test_address.py
index 4e3c889f..66114721 100644
--- a/tests/providers/test_address.py
+++ b/tests/providers/test_address.py
@@ -1029,6 +1029,18 @@ class TestPtBr(unittest.TestCase):
         address = self.fake.address()
         assert isinstance(address, str)
 
+    def test_raw_postcode(self):
+        for _ in range(100):
+            postcode = self.fake.postcode(formatted=False)
+            assert isinstance(postcode, str)
+            assert re.match(r'^\d{8}$', postcode)
+
+    def test_formatted_postcode(self):
+        for _ in range(100):
+            postcode = self.fake.postcode()
+            assert isinstance(postcode, str)
+            assert re.match(r'^\d{5}-?\d{3}$', postcode)
+
 
 class TestPtPT(unittest.TestCase):
 
diff --git a/tests/providers/test_person.py b/tests/providers/test_person.py
index dfc314fd..cbcb28bf 100644
--- a/tests/providers/test_person.py
+++ b/tests/providers/test_person.py
@@ -252,7 +252,7 @@ class TestPlPL(unittest.TestCase):
     @staticmethod
     def validate_nip(nip_str):
         """
-        Validates NIP using recomended code
+        Validates NIP using recommended code
         https://pl.wikibooks.org/wiki/Kody_%C5%BAr%C3%B3d%C5%82owe/Implementacja_NIP
         """
         nip_str = nip_str.replace('-', '')
diff --git a/tests/providers/test_phone_number.py b/tests/providers/test_phone_number.py
index 3f197259..5baa268b 100644
--- a/tests/providers/test_phone_number.py
+++ b/tests/providers/test_phone_number.py
@@ -17,6 +17,13 @@ class TestPhoneNumber(unittest.TestCase):
         assert pn
         assert isinstance(pn, str)
 
+    def test_country_calling_code(self):
+        cc = self.fake.country_calling_code()
+
+        assert cc
+        assert isinstance(cc, str)
+        assert cc.startswith('+')
+
     def test_msisdn(self):
         msisdn = self.fake.msisdn()