PyPaf 0.7.0__tar.gz → 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. {pypaf-0.7.0/src/PyPaf.egg-info → PyPaf-1.0.0}/PKG-INFO +28 -28
  2. {pypaf-0.7.0 → PyPaf-1.0.0}/README.md +26 -26
  3. {pypaf-0.7.0 → PyPaf-1.0.0/src/PyPaf.egg-info}/PKG-INFO +28 -28
  4. {pypaf-0.7.0 → PyPaf-1.0.0}/src/PyPaf.egg-info/SOURCES.txt +4 -2
  5. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/address.py +5 -4
  6. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/attribute.py +9 -8
  7. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/immutable.py +1 -0
  8. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/initiator.py +6 -1
  9. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/lineable.py +1 -0
  10. pypaf-0.7.0/src/paf/premises/premises.py → PyPaf-1.0.0/src/paf/premises/__init__.py +18 -9
  11. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/premises/attribute.py +7 -6
  12. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/premises/building_type.py +6 -2
  13. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/premises/dependent_premisable.py +1 -0
  14. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/premises/exception.py +6 -5
  15. PyPaf-1.0.0/src/paf/premises/extender.py +26 -0
  16. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/premises/lineable.py +5 -1
  17. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/premises/premisable.py +1 -0
  18. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/premises/rule000.py +1 -0
  19. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/premises/rule001.py +1 -0
  20. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/premises/rule010.py +5 -1
  21. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/premises/rule011.py +1 -0
  22. PyPaf-1.0.0/src/paf/premises/rule100.py +47 -0
  23. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/premises/rule101.py +1 -0
  24. PyPaf-1.0.0/src/paf/premises/rule110.py +29 -0
  25. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/premises/rule111.py +3 -2
  26. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/premises/split.py +2 -1
  27. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/thoroughfare_locality.py +5 -5
  28. PyPaf-1.0.0/src/paf/version.py +3 -0
  29. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_empty.py +5 -2
  30. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_exception_i.py +9 -3
  31. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_exception_ii.py +10 -3
  32. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_exception_iii.py +10 -3
  33. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_exception_iv.py +60 -18
  34. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_immutability.py +5 -2
  35. PyPaf-1.0.0/tests/test_kwargs.py +73 -0
  36. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_mainfile.py +5 -2
  37. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_po_box.py +10 -3
  38. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_premises.py +22 -9
  39. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_rule_1.py +5 -2
  40. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_rule_2.py +11 -4
  41. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_rule_3.py +63 -18
  42. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_rule_4.py +17 -4
  43. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_rule_5.py +27 -8
  44. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_rule_6.py +130 -14
  45. {pypaf-0.7.0 → PyPaf-1.0.0}/tests/test_rule_7.py +56 -12
  46. PyPaf-1.0.0/tests/test_rule_x.py +130 -0
  47. pypaf-0.7.0/src/paf/premises/__init__.py +0 -0
  48. pypaf-0.7.0/src/paf/premises/extender.py +0 -24
  49. pypaf-0.7.0/src/paf/premises/rule110.py +0 -20
  50. pypaf-0.7.0/src/paf/version.py +0 -3
  51. {pypaf-0.7.0 → PyPaf-1.0.0}/LICENSE.txt +0 -0
  52. {pypaf-0.7.0 → PyPaf-1.0.0}/pyproject.toml +0 -0
  53. {pypaf-0.7.0 → PyPaf-1.0.0}/setup.cfg +0 -0
  54. {pypaf-0.7.0 → PyPaf-1.0.0}/src/PyPaf.egg-info/dependency_links.txt +0 -0
  55. {pypaf-0.7.0 → PyPaf-1.0.0}/src/PyPaf.egg-info/top_level.txt +0 -0
  56. {pypaf-0.7.0 → PyPaf-1.0.0}/src/paf/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.1
2
2
  Name: PyPaf
3
- Version: 0.7.0
3
+ Version: 1.0.0
4
4
  Summary: Formats the elements of a Royal Mail Postcode Address File entry
5
5
  Author-email: John Bard <johnbard@globalnet.co.uk>
6
6
  License: MIT
@@ -27,7 +27,7 @@ Install it from PyPI:
27
27
 
28
28
  ### Formatting
29
29
 
30
- May be used to format the PAF Address elements as a list of strings:
30
+ May be used to format the PAF Address elements - passed as either a single dictionary or as a series of keyword arguments - as a list of strings:
31
31
 
32
32
  ```python
33
33
  import paf
@@ -48,14 +48,14 @@ Or as a tuple of strings:
48
48
 
49
49
  ```python
50
50
  import paf
51
- address = paf.Address({
52
- 'building_name': "1-2",
53
- 'thoroughfare_name': "NURSERY",
54
- 'thoroughfare_descriptor': "LANE",
55
- 'dependent_locality': "PENN",
56
- 'post_town': "HIGH WYCOMBE",
57
- 'postcode': "HP10 8LS"
58
- })
51
+ address = paf.Address(
52
+ building_name="1-2",
53
+ thoroughfare_name="NURSERY",
54
+ thoroughfare_descriptor="LANE",
55
+ dependent_locality="PENN",
56
+ post_town="HIGH WYCOMBE",
57
+ postcode="HP10 8LS"
58
+ )
59
59
  address.as_tuple() # or tuple(address)
60
60
 
61
61
  ('1-2 NURSERY LANE', 'PENN', 'HIGH WYCOMBE', 'HP10 8LS')
@@ -82,14 +82,14 @@ Or as a dictionary:
82
82
 
83
83
  ```python
84
84
  import paf
85
- address = paf.Address({
86
- 'building_name': "1-2",
87
- 'thoroughfare_name': "NURSERY",
88
- 'thoroughfare_descriptor': "LANE",
89
- 'dependent_locality': "PENN",
90
- 'post_town': "HIGH WYCOMBE",
91
- 'postcode': "HP10 8LS"
92
- })
85
+ address = paf.Address(
86
+ building_name="1-2",
87
+ thoroughfare_name="NURSERY",
88
+ thoroughfare_descriptor="LANE",
89
+ dependent_locality="PENN",
90
+ post_town="HIGH WYCOMBE",
91
+ postcode="HP10 8LS"
92
+ )
93
93
  address.as_dict()
94
94
 
95
95
  {
@@ -147,15 +147,15 @@ If there is no `sub_building_name` element and the `dependent_thoroughfare` elem
147
147
 
148
148
  ```python
149
149
  import paf
150
- self.address = paf.Address({
151
- 'building_name': "1A",
152
- 'dependent_thoroughfare_name': "SEASTONE",
153
- 'dependent_thoroughfare_descriptor': "COURT",
154
- 'thoroughfare_name': "STATION",
155
- 'thoroughfare_descriptor': "ROAD",
156
- 'post_town': "HOLT",
157
- 'postcode': "NR25 7HG"
158
- })
150
+ self.address = paf.Address(
151
+ building_name="1A",
152
+ dependent_thoroughfare_name="SEASTONE",
153
+ dependent_thoroughfare_descriptor="COURT",
154
+ thoroughfare_name="STATION",
155
+ thoroughfare_descriptor="ROAD",
156
+ post_town="HOLT",
157
+ postcode="NR25 7HG"
158
+ )
159
159
  address.premises()
160
160
 
161
161
  {
@@ -12,7 +12,7 @@ Install it from PyPI:
12
12
 
13
13
  ### Formatting
14
14
 
15
- May be used to format the PAF Address elements as a list of strings:
15
+ May be used to format the PAF Address elements - passed as either a single dictionary or as a series of keyword arguments - as a list of strings:
16
16
 
17
17
  ```python
18
18
  import paf
@@ -33,14 +33,14 @@ Or as a tuple of strings:
33
33
 
34
34
  ```python
35
35
  import paf
36
- address = paf.Address({
37
- 'building_name': "1-2",
38
- 'thoroughfare_name': "NURSERY",
39
- 'thoroughfare_descriptor': "LANE",
40
- 'dependent_locality': "PENN",
41
- 'post_town': "HIGH WYCOMBE",
42
- 'postcode': "HP10 8LS"
43
- })
36
+ address = paf.Address(
37
+ building_name="1-2",
38
+ thoroughfare_name="NURSERY",
39
+ thoroughfare_descriptor="LANE",
40
+ dependent_locality="PENN",
41
+ post_town="HIGH WYCOMBE",
42
+ postcode="HP10 8LS"
43
+ )
44
44
  address.as_tuple() # or tuple(address)
45
45
 
46
46
  ('1-2 NURSERY LANE', 'PENN', 'HIGH WYCOMBE', 'HP10 8LS')
@@ -67,14 +67,14 @@ Or as a dictionary:
67
67
 
68
68
  ```python
69
69
  import paf
70
- address = paf.Address({
71
- 'building_name': "1-2",
72
- 'thoroughfare_name': "NURSERY",
73
- 'thoroughfare_descriptor': "LANE",
74
- 'dependent_locality': "PENN",
75
- 'post_town': "HIGH WYCOMBE",
76
- 'postcode': "HP10 8LS"
77
- })
70
+ address = paf.Address(
71
+ building_name="1-2",
72
+ thoroughfare_name="NURSERY",
73
+ thoroughfare_descriptor="LANE",
74
+ dependent_locality="PENN",
75
+ post_town="HIGH WYCOMBE",
76
+ postcode="HP10 8LS"
77
+ )
78
78
  address.as_dict()
79
79
 
80
80
  {
@@ -132,15 +132,15 @@ If there is no `sub_building_name` element and the `dependent_thoroughfare` elem
132
132
 
133
133
  ```python
134
134
  import paf
135
- self.address = paf.Address({
136
- 'building_name': "1A",
137
- 'dependent_thoroughfare_name': "SEASTONE",
138
- 'dependent_thoroughfare_descriptor': "COURT",
139
- 'thoroughfare_name': "STATION",
140
- 'thoroughfare_descriptor': "ROAD",
141
- 'post_town': "HOLT",
142
- 'postcode': "NR25 7HG"
143
- })
135
+ self.address = paf.Address(
136
+ building_name="1A",
137
+ dependent_thoroughfare_name="SEASTONE",
138
+ dependent_thoroughfare_descriptor="COURT",
139
+ thoroughfare_name="STATION",
140
+ thoroughfare_descriptor="ROAD",
141
+ post_town="HOLT",
142
+ postcode="NR25 7HG"
143
+ )
144
144
  address.premises()
145
145
 
146
146
  {
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.1
2
2
  Name: PyPaf
3
- Version: 0.7.0
3
+ Version: 1.0.0
4
4
  Summary: Formats the elements of a Royal Mail Postcode Address File entry
5
5
  Author-email: John Bard <johnbard@globalnet.co.uk>
6
6
  License: MIT
@@ -27,7 +27,7 @@ Install it from PyPI:
27
27
 
28
28
  ### Formatting
29
29
 
30
- May be used to format the PAF Address elements as a list of strings:
30
+ May be used to format the PAF Address elements - passed as either a single dictionary or as a series of keyword arguments - as a list of strings:
31
31
 
32
32
  ```python
33
33
  import paf
@@ -48,14 +48,14 @@ Or as a tuple of strings:
48
48
 
49
49
  ```python
50
50
  import paf
51
- address = paf.Address({
52
- 'building_name': "1-2",
53
- 'thoroughfare_name': "NURSERY",
54
- 'thoroughfare_descriptor': "LANE",
55
- 'dependent_locality': "PENN",
56
- 'post_town': "HIGH WYCOMBE",
57
- 'postcode': "HP10 8LS"
58
- })
51
+ address = paf.Address(
52
+ building_name="1-2",
53
+ thoroughfare_name="NURSERY",
54
+ thoroughfare_descriptor="LANE",
55
+ dependent_locality="PENN",
56
+ post_town="HIGH WYCOMBE",
57
+ postcode="HP10 8LS"
58
+ )
59
59
  address.as_tuple() # or tuple(address)
60
60
 
61
61
  ('1-2 NURSERY LANE', 'PENN', 'HIGH WYCOMBE', 'HP10 8LS')
@@ -82,14 +82,14 @@ Or as a dictionary:
82
82
 
83
83
  ```python
84
84
  import paf
85
- address = paf.Address({
86
- 'building_name': "1-2",
87
- 'thoroughfare_name': "NURSERY",
88
- 'thoroughfare_descriptor': "LANE",
89
- 'dependent_locality': "PENN",
90
- 'post_town': "HIGH WYCOMBE",
91
- 'postcode': "HP10 8LS"
92
- })
85
+ address = paf.Address(
86
+ building_name="1-2",
87
+ thoroughfare_name="NURSERY",
88
+ thoroughfare_descriptor="LANE",
89
+ dependent_locality="PENN",
90
+ post_town="HIGH WYCOMBE",
91
+ postcode="HP10 8LS"
92
+ )
93
93
  address.as_dict()
94
94
 
95
95
  {
@@ -147,15 +147,15 @@ If there is no `sub_building_name` element and the `dependent_thoroughfare` elem
147
147
 
148
148
  ```python
149
149
  import paf
150
- self.address = paf.Address({
151
- 'building_name': "1A",
152
- 'dependent_thoroughfare_name': "SEASTONE",
153
- 'dependent_thoroughfare_descriptor': "COURT",
154
- 'thoroughfare_name': "STATION",
155
- 'thoroughfare_descriptor': "ROAD",
156
- 'post_town': "HOLT",
157
- 'postcode': "NR25 7HG"
158
- })
150
+ self.address = paf.Address(
151
+ building_name="1A",
152
+ dependent_thoroughfare_name="SEASTONE",
153
+ dependent_thoroughfare_descriptor="COURT",
154
+ thoroughfare_name="STATION",
155
+ thoroughfare_descriptor="ROAD",
156
+ post_town="HOLT",
157
+ postcode="NR25 7HG"
158
+ )
159
159
  address.premises()
160
160
 
161
161
  {
@@ -21,11 +21,11 @@ src/paf/premises/exception.py
21
21
  src/paf/premises/extender.py
22
22
  src/paf/premises/lineable.py
23
23
  src/paf/premises/premisable.py
24
- src/paf/premises/premises.py
25
24
  src/paf/premises/rule000.py
26
25
  src/paf/premises/rule001.py
27
26
  src/paf/premises/rule010.py
28
27
  src/paf/premises/rule011.py
28
+ src/paf/premises/rule100.py
29
29
  src/paf/premises/rule101.py
30
30
  src/paf/premises/rule110.py
31
31
  src/paf/premises/rule111.py
@@ -36,6 +36,7 @@ tests/test_exception_ii.py
36
36
  tests/test_exception_iii.py
37
37
  tests/test_exception_iv.py
38
38
  tests/test_immutability.py
39
+ tests/test_kwargs.py
39
40
  tests/test_mainfile.py
40
41
  tests/test_po_box.py
41
42
  tests/test_premises.py
@@ -45,4 +46,5 @@ tests/test_rule_3.py
45
46
  tests/test_rule_4.py
46
47
  tests/test_rule_5.py
47
48
  tests/test_rule_6.py
48
- tests/test_rule_7.py
49
+ tests/test_rule_7.py
50
+ tests/test_rule_x.py
@@ -1,20 +1,21 @@
1
1
  """PAF Address"""
2
2
 
3
- # Tried using dataclasses.dataclass(frozen=True) decorator for immutablity but did not work"""
3
+ # Tried dataclasses.dataclass(frozen=True) for immutablity but did not work"""
4
4
  from .initiator import attribute_init
5
5
  from .attribute import AttributeMixin
6
6
  from .immutable import ImmutableMixin
7
7
  from .lineable import LineableMixin
8
8
  from .thoroughfare_locality import ThoroughfareLocalityMixin
9
- from .premises.premises import Premises
9
+ from .premises import Premises
10
+
10
11
 
11
12
  class Address(ImmutableMixin, AttributeMixin, ThoroughfareLocalityMixin, LineableMixin):
12
13
  """Main PAF Address class"""
13
14
 
14
15
  @attribute_init
15
- def __init__(self, *args):
16
+ def __init__(self, *args, **kwargs):
16
17
  """Initialise Address elements"""
17
- object.__setattr__(self, 'premises', Premises(*args))
18
+ object.__setattr__(self, 'premises', Premises(*args, **kwargs))
18
19
 
19
20
  def __repr__(self):
20
21
  """Return full representation of an Address"""
@@ -1,5 +1,6 @@
1
1
  """Attribute Mixin"""
2
2
 
3
+
3
4
  class AttributeMixin():
4
5
  """Address elements and derived properties"""
5
6
 
@@ -9,8 +10,8 @@ class AttributeMixin():
9
10
  """Returns Paf premises elements"""
10
11
  return (
11
12
  'organisation_name', 'department_name',
12
- 'sub_building_name', 'building_name', 'building_number',
13
- 'po_box_number'
13
+ 'sub_building_name', 'building_name', 'building_number',
14
+ 'po_box_number'
14
15
  )
15
16
 
16
17
  @classmethod
@@ -29,13 +30,13 @@ class AttributeMixin():
29
30
  @property
30
31
  def attrs(cls):
31
32
  """Returns all Paf address elements"""
32
- return(
33
+ return (
33
34
  cls.premises_attrs
34
- + cls.dependent_thoroughfare_attrs
35
- + cls.thoroughfare_attrs
36
- + cls.locality_attrs
37
- + cls.post_attrs
38
- + cls.other_attrs
35
+ + cls.dependent_thoroughfare_attrs
36
+ + cls.thoroughfare_attrs
37
+ + cls.locality_attrs
38
+ + cls.post_attrs
39
+ + cls.other_attrs
39
40
  )
40
41
 
41
42
  def is_empty(self, attr):
@@ -2,6 +2,7 @@
2
2
 
3
3
  from dataclasses import FrozenInstanceError
4
4
 
5
+
5
6
  class ImmutableMixin():
6
7
  """Prevent manipulation of object attributes"""
7
8
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  import functools
4
4
 
5
+
5
6
  def attribute_init(func):
6
7
  """Decorator to initiate an object based on a list of attributes"""
7
8
 
@@ -10,7 +11,11 @@ def attribute_init(func):
10
11
  """Initiate properties from specified dict"""
11
12
  for key in list(getattr(self, 'attrs', [])):
12
13
  object.__setattr__(self, key, '')
13
- for key, val in args[0].items():
14
+ if kwargs:
15
+ elements = kwargs
16
+ else:
17
+ elements = args[0]
18
+ for key, val in elements.items():
14
19
  if hasattr(self, key):
15
20
  object.__setattr__(self, key, str(val))
16
21
  return func(self, *args, **kwargs)
@@ -2,6 +2,7 @@
2
2
 
3
3
  from itertools import chain
4
4
 
5
+
5
6
  class LineableMixin():
6
7
  """Converts Paf address elements into list of address lines"""
7
8
 
@@ -8,14 +8,15 @@ from .extender import ExtenderMixin
8
8
  from .lineable import LineableMixin
9
9
  from .split import SplitMixin
10
10
 
11
+
11
12
  class Premises(
12
- ImmutableMixin, ExtenderMixin, AttributeMixin,
13
+ ImmutableMixin, ExtenderMixin, AttributeMixin,
13
14
  ThoroughfareLocalityMixin, LineableMixin, SplitMixin
14
- ):
15
+ ):
15
16
  """PAF Address Premises class"""
16
17
 
17
18
  @attribute_init
18
- def __init__(self, *args): # pylint: disable=unused-argument
19
+ def __init__(self, *args, **kwargs): # pylint: disable=unused-argument
19
20
  """Initialise Premises elements"""
20
21
  self.extend()
21
22
 
@@ -34,7 +35,7 @@ class Premises(
34
35
 
35
36
  def __call__(self):
36
37
  """Return Premises as dictionary"""
37
- return self.as_premisable() # pylint: disable=no-member
38
+ return self.as_premisable() # pylint: disable=no-member
38
39
 
39
40
  @property
40
41
  def building_number_and_sub_building_name(self):
@@ -48,16 +49,17 @@ class Premises(
48
49
 
49
50
  @property
50
51
  def name_last_word_and_thoroughfare_or_locality(self):
51
- """Returns last word of building name and first thoroughfare or locality"""
52
+ """Returns last word of building name and first thoroughfare"""
52
53
  return self._concatenate(('building_name_last_word', 'first_thoroughfare_or_locality'))
53
54
 
54
55
  @property
55
56
  def number_and_thoroughfare_or_locality(self):
56
57
  """Returns building number and first thoroughfare or locality"""
57
58
  return self._concatenate(('building_number', 'first_thoroughfare_or_locality'))
59
+
58
60
  @property
59
61
  def number_sub_name_and_thoroughfare_or_locality(self):
60
- """Returns building number, sub-building name and first thoroughfare or locality"""
62
+ """Returns building number, sub-building name and first thoroughfare"""
61
63
  return self._concatenate(
62
64
  ('building_number_and_sub_building_name', 'first_thoroughfare_or_locality')
63
65
  )
@@ -69,9 +71,14 @@ class Premises(
69
71
 
70
72
  @property
71
73
  def sub_name_comma_name(self):
72
- """Returns sub-building name and building name concatenated with a comma"""
74
+ """Returns sub-building name and building name joined with a comma"""
73
75
  return self._concatenate(('sub_building_name', 'building_name'), ', ')
74
76
 
77
+ @property
78
+ def sub_name_and_thoroughfare_or_locality(self):
79
+ """Returns sub-building number and first thoroughfare or locality"""
80
+ return self._concatenate(('sub_building_name', 'first_thoroughfare_or_locality'))
81
+
75
82
  @property
76
83
  def building_name_but_last_word(self):
77
84
  """Returns all but last word of the building name"""
@@ -93,5 +100,7 @@ class Premises(
93
100
  return self.last_word('sub_building_name')
94
101
 
95
102
  def _concatenate(self, keys, concatenator=' '):
96
- """Returns specified attributes concatenated with a specified separator"""
97
- return concatenator.join(filter(None, [getattr(self, k, None) for k in keys]))
103
+ """Returns specified attributes concatenated with a separator"""
104
+ return concatenator.join(
105
+ filter(None, [getattr(self, k, None) for k in keys])
106
+ )
@@ -1,5 +1,6 @@
1
1
  """Attribute Mixin"""
2
2
 
3
+
3
4
  class AttributeMixin():
4
5
  """Premises elements and derived properties"""
5
6
 
@@ -25,13 +26,13 @@ class AttributeMixin():
25
26
  @property
26
27
  def attrs(cls):
27
28
  """Returns all Paf premises elements"""
28
- return(
29
+ return (
29
30
  cls.organisation_attrs
30
- + cls.building_attrs
31
- + cls.dependent_thoroughfare_attrs
32
- + cls.thoroughfare_attrs
33
- + cls.locality_attrs
34
- + cls.other_attrs
31
+ + cls.building_attrs
32
+ + cls.dependent_thoroughfare_attrs
33
+ + cls.thoroughfare_attrs
34
+ + cls.locality_attrs
35
+ + cls.other_attrs
35
36
  )
36
37
 
37
38
  def is_empty(self, attr):
@@ -2,6 +2,7 @@
2
2
 
3
3
  from .split import SplitMixin
4
4
 
5
+
5
6
  class BuildingTypeMixin(SplitMixin):
6
7
  """Determines if a string represents a known building type"""
7
8
 
@@ -10,8 +11,11 @@ class BuildingTypeMixin(SplitMixin):
10
11
  def known_building_types(cls):
11
12
  """Returns known building types"""
12
13
  return (
13
- "BACK OF", "BLOCK", "BLOCKS", "BUILDING", "MAISONETTE", "MAISONETTES", "REAR OF",
14
- "SHOP", "SHOPS", "STALL", "STALLS", "SUITE", "SUITES", "UNIT", "UNITS", "PO BOX"
14
+ "BACK OF", "BLOCK", "BLOCKS", "BUILDING",
15
+ "MAISONETTE", "MAISONETTES", "REAR OF",
16
+ "SHOP", "SHOPS", "STALL", "STALLS",
17
+ "SUITE", "SUITES", "UNIT", "UNITS",
18
+ "PO BOX"
15
19
  )
16
20
 
17
21
  @classmethod
@@ -2,6 +2,7 @@
2
2
 
3
3
  from .premisable import PremisableMixin
4
4
 
5
+
5
6
  class DependentPremisableMixin(PremisableMixin):
6
7
  """Returns the values for the premises properties"""
7
8
 
@@ -4,6 +4,7 @@ import re
4
4
  from .building_type import BuildingTypeMixin
5
5
  from .split import SplitMixin
6
6
 
7
+
7
8
  class ExceptionMixin(BuildingTypeMixin, SplitMixin):
8
9
  """Exceptions"""
9
10
 
@@ -27,8 +28,8 @@ class ExceptionMixin(BuildingTypeMixin, SplitMixin):
27
28
  """Returns if value is an exception"""
28
29
  return (
29
30
  cls.__is_exception_i(val)
30
- or cls.__is_exception_ii(val)
31
- or cls.__is_exception_iii(val)
31
+ or cls.__is_exception_ii(val)
32
+ or cls.__is_exception_iii(val)
32
33
  )
33
34
 
34
35
  def __is_exception_iv(self, attr): # pylint: disable=unused-argument
@@ -36,7 +37,7 @@ class ExceptionMixin(BuildingTypeMixin, SplitMixin):
36
37
  and ends with numeric range or numeric alpha suffix"""
37
38
  # Do not include suffix check as does not account for values such as BLOCK B
38
39
  return self.is_known_building_type(attr)
39
- # and re.match(r'^\d', splitstring.last_word(getattr(self, attr, None)))
40
+ # and re.match(r'^\d', self.last_word(attr))
40
41
 
41
42
  def is_exception(self, attr):
42
43
  """Returns if attribute is an exception"""
@@ -46,6 +47,6 @@ class ExceptionMixin(BuildingTypeMixin, SplitMixin):
46
47
  """Returns if attribute should be split"""
47
48
  return (
48
49
  self.__is_exception(self.last_word(attr))
49
- and not self.last_word(attr).isdigit()
50
- and not self.__is_exception_iv(attr)
50
+ and not self.last_word(attr).isdigit()
51
+ and not self.__is_exception_iv(attr)
51
52
  )
@@ -0,0 +1,26 @@
1
+ """Premises Extender Mixin"""
2
+
3
+ import sys
4
+ from .rule000 import Rule000 # pylint: disable=unused-import # noqa: F401
5
+ from .rule001 import Rule001 # pylint: disable=unused-import # noqa: F401
6
+ from .rule010 import Rule010 # pylint: disable=unused-import # noqa: F401
7
+ from .rule100 import Rule100 # pylint: disable=unused-import # noqa: F401
8
+ from .rule011 import Rule011 # pylint: disable=unused-import # noqa: F401
9
+ from .rule101 import Rule101 # pylint: disable=unused-import # noqa: F401
10
+ from .rule110 import Rule110 # pylint: disable=unused-import # noqa: F401
11
+ from .rule111 import Rule111 # pylint: disable=unused-import # noqa: F401
12
+
13
+
14
+ class ExtenderMixin():
15
+ """Dynamic Premises processing"""
16
+
17
+ @property
18
+ def rule(self):
19
+ """Returns premises rule class"""
20
+ rule = ''.join(['0' if self.is_empty(k) else '1' for k in self.building_attrs])
21
+ return getattr(sys.modules[__name__], 'Rule' + rule)
22
+
23
+ def extend(self):
24
+ """Dynamically extends instance with appropriate rule"""
25
+ base_cls = self.__class__
26
+ object.__setattr__(self, '__class__', type(base_cls.__name__, (base_cls, self.rule), {}))
@@ -2,6 +2,7 @@
2
2
 
3
3
  from itertools import chain
4
4
 
5
+
5
6
  class LineableMixin():
6
7
  """Converts Paf address premises elements into list of lines"""
7
8
 
@@ -18,7 +19,10 @@ class LineableMixin():
18
19
  @property
19
20
  def po_box(self):
20
21
  """Returns PO Box"""
21
- return '' if self.is_empty('po_box_number') else f"PO BOX {getattr(self, 'po_box_number')}"
22
+ return (
23
+ '' if self.is_empty('po_box_number')
24
+ else f"PO BOX {getattr(self, 'po_box_number')}"
25
+ )
22
26
 
23
27
  def _lines(self, attrs):
24
28
  """Returns list of premises lines from specified attributes"""
@@ -2,6 +2,7 @@
2
2
 
3
3
  from .exception import ExceptionMixin
4
4
 
5
+
5
6
  class PremisableMixin(ExceptionMixin):
6
7
  """Returns the values for the premises properties"""
7
8
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  from .premisable import PremisableMixin
4
4
 
5
+
5
6
  class Rule000(PremisableMixin):
6
7
  """Rule 1 processing"""
7
8
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  from .dependent_premisable import DependentPremisableMixin
4
4
 
5
+
5
6
  class Rule001(DependentPremisableMixin):
6
7
  """Rule 2 processing"""
7
8
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  from .dependent_premisable import DependentPremisableMixin
4
4
 
5
+
5
6
  class Rule010(DependentPremisableMixin):
6
7
  """Rule 3 processing"""
7
8
 
@@ -17,4 +18,7 @@ class Rule010(DependentPremisableMixin):
17
18
  @property
18
19
  def includes_first_thoroughfare_or_locality(self):
19
20
  """Returns if premises includes first thoroughfare or locality"""
20
- return self.is_exception('building_name') or self.is_split_exception('building_name')
21
+ return (
22
+ self.is_exception('building_name')
23
+ or self.is_split_exception('building_name')
24
+ )
@@ -2,6 +2,7 @@
2
2
 
3
3
  from .dependent_premisable import DependentPremisableMixin
4
4
 
5
+
5
6
  class Rule011(DependentPremisableMixin):
6
7
  """Rule 4 processing"""
7
8