PyPaf 0.1.0__py3-none-any.whl
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.
- PyPaf-0.1.0.dist-info/LICENSE.txt +21 -0
- PyPaf-0.1.0.dist-info/METADATA +72 -0
- PyPaf-0.1.0.dist-info/RECORD +21 -0
- PyPaf-0.1.0.dist-info/WHEEL +5 -0
- PyPaf-0.1.0.dist-info/top_level.txt +1 -0
- paf/__init__.py +6 -0
- paf/attribute.py +66 -0
- paf/lineable.py +27 -0
- paf/paf.py +33 -0
- paf/premises/__init__.py +0 -0
- paf/premises/common.py +38 -0
- paf/premises/rule000.py +16 -0
- paf/premises/rule001.py +16 -0
- paf/premises/rule010.py +46 -0
- paf/premises/rule011.py +16 -0
- paf/premises/rule101.py +30 -0
- paf/premises/rule110.py +20 -0
- paf/premises/rule111.py +18 -0
- paf/premises_extender.py +25 -0
- paf/thoroughfare_locality.py +51 -0
- paf/version.py +3 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 John Bard
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: PyPaf
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Formats the elements of a Royal Mail Postcode Address File entry
|
|
5
|
+
Author-email: John Bard <johnbard@globalnet.co.uk>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/drabjay/pypaf
|
|
8
|
+
Project-URL: Repository, https://github.com/drabjay/pypaf.git
|
|
9
|
+
Project-URL: Issues, https://github.com/drabjay/paf/issues
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.8
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE.txt
|
|
15
|
+
|
|
16
|
+
# PyPaf
|
|
17
|
+
|
|
18
|
+
Formats the elements of a Royal Mail Postcode Address File entry according to the rules described in the [Royal Mail Programmer's Guide Edition 7, Version 5.0](http://www.royalmail.com/sites/default/files/docs/pdf/programmers_guide_edition_7_v5.pdf)
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
Install it from PyPI:
|
|
23
|
+
|
|
24
|
+
$ pip install pypaf
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
May be used to format the PAF elements as an array of strings:
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from paf import Paf
|
|
32
|
+
paf = Paf({
|
|
33
|
+
'building_name': "1-2",
|
|
34
|
+
'thoroughfare_name': "NURSERY",
|
|
35
|
+
'thoroughfare_descriptor': "LANE",
|
|
36
|
+
'dependent_locality': "PENN",
|
|
37
|
+
'post_town': "HIGH WYCOMBE",
|
|
38
|
+
'postcode': "HP10 8LS"
|
|
39
|
+
})
|
|
40
|
+
paf.list()
|
|
41
|
+
|
|
42
|
+
['1-2 NURSERY LANE', 'PENN', 'HIGH WYCOMBE', 'HP10 8LS']
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Or as a single string:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from paf import Paf
|
|
49
|
+
paf = Paf({
|
|
50
|
+
'building_name': "1-2",
|
|
51
|
+
'thoroughfare_name': "NURSERY",
|
|
52
|
+
'thoroughfare_descriptor': "LANE",
|
|
53
|
+
'dependent_locality': "PENN",
|
|
54
|
+
'post_town': "HIGH WYCOMBE",
|
|
55
|
+
'postcode': "HP10 8LS"
|
|
56
|
+
})
|
|
57
|
+
str(paf)
|
|
58
|
+
|
|
59
|
+
'1-2 NURSERY LANE, PENN, HIGH WYCOMBE. HP10 8LS'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Contributing
|
|
63
|
+
|
|
64
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/drabjay/pypaf. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
|
65
|
+
|
|
66
|
+
## License
|
|
67
|
+
|
|
68
|
+
The package is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
|
69
|
+
|
|
70
|
+
## Code of Conduct
|
|
71
|
+
|
|
72
|
+
Everyone interacting in the PyPaf project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/drabjayc/pypaf/blob/master/CODE_OF_CONDUCT.md).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
paf/__init__.py,sha256=w2HsvPirX6Zw95ZHBiYjUpHDHvwmN-O6zggCvhGuRLE,109
|
|
2
|
+
paf/attribute.py,sha256=MDMBDxuTvniQt0UWgMB2dslg4hajVYjm8pMHW2In8tk,1890
|
|
3
|
+
paf/lineable.py,sha256=L-6zi9h6IrUDw2hwRUPRa65MRe82pXcOxu4essEKoyE,948
|
|
4
|
+
paf/paf.py,sha256=eQoFBj1hJDZKpOJzNPhRYdHiN91iIqkjhCeRBHD6Ko4,1035
|
|
5
|
+
paf/premises_extender.py,sha256=CusZwvXYAC8GH0_NgDEf9fkpcxVkrpNW5wEcw_A-g8E,1124
|
|
6
|
+
paf/thoroughfare_locality.py,sha256=0A8xJ7JrVHHXMh2yr8oBqX8Ec2Br10ZrK7ujawQ_1yQ,1866
|
|
7
|
+
paf/version.py,sha256=I7CCHRp7v4pFRh5W5cdIJIuET_tRwULAKmJT230wB3E,37
|
|
8
|
+
paf/premises/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
paf/premises/common.py,sha256=0BLCMLwZU1yJTuXeHhQKzYpnxQOcJDp2m_CUvsiKXBE,1358
|
|
10
|
+
paf/premises/rule000.py,sha256=kzzHNJ2wxgXuJSqu4VyNizBre2aCtWpqFnAuUMOX5Nc,375
|
|
11
|
+
paf/premises/rule001.py,sha256=B6QOIkbeAMwae3xHrjqaMPiPi8zitpxKM5m1K3FP8TI,411
|
|
12
|
+
paf/premises/rule010.py,sha256=AtvnwcW6O_xb72awazHcQXVduMTcnRCbE_P3LvP1zjM,1656
|
|
13
|
+
paf/premises/rule011.py,sha256=2rF4COJkuycD9uhbkcokMotFAWtBrWfCLBE3-aT5xwY,428
|
|
14
|
+
paf/premises/rule101.py,sha256=4Ml3BQz2LKyT4Of809el6exVBjFz5Ox1VlnRS1ivc0Q,1075
|
|
15
|
+
paf/premises/rule110.py,sha256=dZjhPJlV3z3DbFxBuxRRm8SwxlnRuvIEbiKPRuwxLgg,704
|
|
16
|
+
paf/premises/rule111.py,sha256=_A4zdMc8B4uqtb-JlvhpUZebckmYRtyZGCwzACTztiA,579
|
|
17
|
+
PyPaf-0.1.0.dist-info/LICENSE.txt,sha256=mS-ROSs81MzkitAWqX9Mw16kRQ1mZTWsmJusmZqhUvA,1075
|
|
18
|
+
PyPaf-0.1.0.dist-info/METADATA,sha256=KzcjptRQ6YwnKOexbukSbXTEuZ7mDZ3Tb6xw_7Un-lY,2255
|
|
19
|
+
PyPaf-0.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
20
|
+
PyPaf-0.1.0.dist-info/top_level.txt,sha256=XUoA1HTds1ccl3RQvWR2pX4dcMMKnqryRf1PMZBPz6I,4
|
|
21
|
+
PyPaf-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
paf
|
paf/__init__.py
ADDED
paf/attribute.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Attribute Mixin"""
|
|
2
|
+
|
|
3
|
+
class AttributeMixin():
|
|
4
|
+
"""Base Paf address elements and derived properties"""
|
|
5
|
+
|
|
6
|
+
@classmethod
|
|
7
|
+
@property
|
|
8
|
+
def organisation_attrs(cls):
|
|
9
|
+
"""Returns Paf organisation elements"""
|
|
10
|
+
return ['organisation_name', 'department_name']
|
|
11
|
+
|
|
12
|
+
@classmethod
|
|
13
|
+
@property
|
|
14
|
+
def premises_attrs(cls):
|
|
15
|
+
"""Returns Paf premises elements"""
|
|
16
|
+
return ['sub_building_name', 'building_name', 'building_number']
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
@property
|
|
20
|
+
def dependent_thoroughfare_attrs(cls):
|
|
21
|
+
"""Returns Paf dependent thoroughfare elements"""
|
|
22
|
+
return ['dependent_thoroughfare_name', 'dependent_thoroughfare_descriptor']
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
@property
|
|
26
|
+
def thoroughfare_attrs(cls):
|
|
27
|
+
"""Returns Paf thoroughfare elements"""
|
|
28
|
+
return ['thoroughfare_name', 'thoroughfare_descriptor']
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
@property
|
|
32
|
+
def locality_attrs(cls):
|
|
33
|
+
"""Returns Paf localoty elements"""
|
|
34
|
+
return ['double_dependent_locality', 'dependent_locality']
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
@property
|
|
38
|
+
def post_attrs(cls):
|
|
39
|
+
"""Returns Paf post elements"""
|
|
40
|
+
return ['post_town', 'postcode']
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
@property
|
|
44
|
+
def other_attrs(cls):
|
|
45
|
+
"""Returns Paf other elements"""
|
|
46
|
+
return ['po_box_number', 'udprn', 'concatenation_indicator']
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
@property
|
|
50
|
+
def attrs(cls):
|
|
51
|
+
"""Returns all Paf address elements"""
|
|
52
|
+
return(
|
|
53
|
+
cls.organisation_attrs +
|
|
54
|
+
cls.premises_attrs +
|
|
55
|
+
cls.dependent_thoroughfare_attrs +
|
|
56
|
+
cls.thoroughfare_attrs +
|
|
57
|
+
cls.locality_attrs +
|
|
58
|
+
cls.post_attrs +
|
|
59
|
+
cls.other_attrs
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def is_empty(self, attr):
|
|
63
|
+
"""Returns if attribute value is empty"""
|
|
64
|
+
if getattr(self, attr, '') == '':
|
|
65
|
+
return True
|
|
66
|
+
return False
|
paf/lineable.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Lineable Mixin"""
|
|
2
|
+
|
|
3
|
+
from itertools import chain
|
|
4
|
+
from .thoroughfare_locality import ThoroughfareLocalityMixin
|
|
5
|
+
|
|
6
|
+
class LineableMixin(ThoroughfareLocalityMixin):
|
|
7
|
+
"""Converts Paf address elements into list of address lines, excluding postcode"""
|
|
8
|
+
|
|
9
|
+
@classmethod
|
|
10
|
+
@property
|
|
11
|
+
def lines_attrs(cls):
|
|
12
|
+
"""Returns Paf address line attributes"""
|
|
13
|
+
return(
|
|
14
|
+
cls.organisation_attrs +
|
|
15
|
+
['po_box', 'premises', 'thoroughfares_and_localities', 'post_town']
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def lines(self):
|
|
20
|
+
"""Returns Paf as list of address lines"""
|
|
21
|
+
lines = list(filter(None, [getattr(self, k, None) for k in self.__class__.lines_attrs]))
|
|
22
|
+
return list(chain(*[line if isinstance(line, list) else [line] for line in lines]))
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def po_box(self):
|
|
26
|
+
"""Returns PO Box"""
|
|
27
|
+
return '' if self.is_empty('po_box_number') else f"PO BOX {getattr(self, 'po_box_number')}"
|
paf/paf.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Paf"""
|
|
2
|
+
|
|
3
|
+
from .lineable import LineableMixin
|
|
4
|
+
|
|
5
|
+
class Paf(LineableMixin):
|
|
6
|
+
"""Main Paf class"""
|
|
7
|
+
|
|
8
|
+
def __init__(self, args):
|
|
9
|
+
"""Initialise Paf address elements"""
|
|
10
|
+
for key in self.__class__.attrs:
|
|
11
|
+
setattr(self, key, '')
|
|
12
|
+
for key, val in args.items():
|
|
13
|
+
if hasattr(self, key):
|
|
14
|
+
setattr(self, key, val)
|
|
15
|
+
self.extend_premises()
|
|
16
|
+
|
|
17
|
+
def __repr__(self):
|
|
18
|
+
"""Return full representation of Paf"""
|
|
19
|
+
args = {k: getattr(self, k) for k in self.__class__.attrs if getattr(self, k, None)}
|
|
20
|
+
return self.__class__.__name__ + '(' + str(args) + ')'
|
|
21
|
+
|
|
22
|
+
def __str__(self):
|
|
23
|
+
"""Return Paf as string"""
|
|
24
|
+
line = ', '.join(self.lines)
|
|
25
|
+
if self.is_empty('postcode'):
|
|
26
|
+
return line
|
|
27
|
+
return '. '.join([line] + [getattr(self, 'postcode')])
|
|
28
|
+
|
|
29
|
+
def list(self):
|
|
30
|
+
"""Return Paf as list of strings"""
|
|
31
|
+
if self.is_empty('postcode'):
|
|
32
|
+
return self.lines
|
|
33
|
+
return self.lines + [getattr(self, 'postcode')]
|
paf/premises/__init__.py
ADDED
|
File without changes
|
paf/premises/common.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Common"""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
class Common:
|
|
6
|
+
"""Common premises processing"""
|
|
7
|
+
|
|
8
|
+
@property
|
|
9
|
+
def premises_rule_attrs(self):
|
|
10
|
+
"""Abstract method to be implemented by the Rule"""
|
|
11
|
+
|
|
12
|
+
@property
|
|
13
|
+
def premises(self):
|
|
14
|
+
"""Returns premises list"""
|
|
15
|
+
return [getattr(self, k) for k in self.premises_rule_attrs]
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def name_and_thoroughfare_or_locality(self):
|
|
19
|
+
"""Returns building number and first thoroughfare or locality"""
|
|
20
|
+
return self._concatenate(['building_name', 'first_thoroughfare_or_locality'])
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def number_and_thoroughfare_or_locality(self):
|
|
24
|
+
"""Returns building number and first thoroughfare or locality"""
|
|
25
|
+
return self._concatenate(['building_number', 'first_thoroughfare_or_locality'])
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def sub_name_and_name(self):
|
|
29
|
+
"""Returns sub-building name and building name"""
|
|
30
|
+
return self._concatenate(['sub_building_name', 'building_name'])
|
|
31
|
+
|
|
32
|
+
def is_exception(self, attr):
|
|
33
|
+
"""Returns if value is an exception"""
|
|
34
|
+
return re.match(r'^(.|[\d][a-zA-Z]|[\d].*?[\d][a-zA-Z]?)$', getattr(self, attr, None))
|
|
35
|
+
|
|
36
|
+
def _concatenate(self, keys, concatenator=' '):
|
|
37
|
+
"""Returns specified attributes concatenated with a specified separator"""
|
|
38
|
+
return concatenator.join(filter(None, [getattr(self, k, None) for k in keys]))
|
paf/premises/rule000.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Rule 1"""
|
|
2
|
+
|
|
3
|
+
from .common import Common
|
|
4
|
+
|
|
5
|
+
class Rule000(Common):
|
|
6
|
+
"""Rule 1 processing"""
|
|
7
|
+
|
|
8
|
+
@property
|
|
9
|
+
def premises_rule_attrs(self):
|
|
10
|
+
"""Returns premises list"""
|
|
11
|
+
return []
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def does_premises_include_first_thoroughfare_or_locality(self):
|
|
15
|
+
"""Returns if premises includes first thoroughfare or locality"""
|
|
16
|
+
return False
|
paf/premises/rule001.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Rule 2"""
|
|
2
|
+
|
|
3
|
+
from .common import Common
|
|
4
|
+
|
|
5
|
+
class Rule001(Common):
|
|
6
|
+
"""Rule 2 processing"""
|
|
7
|
+
|
|
8
|
+
@property
|
|
9
|
+
def premises_rule_attrs(self):
|
|
10
|
+
"""Returns premises list"""
|
|
11
|
+
return ['number_and_thoroughfare_or_locality']
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def does_premises_include_first_thoroughfare_or_locality(self):
|
|
15
|
+
"""Returns if premises includes first thoroughfare or locality"""
|
|
16
|
+
return True
|
paf/premises/rule010.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Rule 3"""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from .common import Common
|
|
5
|
+
|
|
6
|
+
class Rule010(Common):
|
|
7
|
+
"""Rule 3 processing"""
|
|
8
|
+
|
|
9
|
+
@property
|
|
10
|
+
def premises_rule_attrs(self):
|
|
11
|
+
"""Returns premises list"""
|
|
12
|
+
if self.is_exception('building_name'):
|
|
13
|
+
return ['name_and_thoroughfare_or_locality']
|
|
14
|
+
if self.is_building_name_split_exception:
|
|
15
|
+
return ['building_name_but_last_word', 'name_last_word_and_thoroughfare_or_locality']
|
|
16
|
+
return ['building_name']
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def does_premises_include_first_thoroughfare_or_locality(self):
|
|
20
|
+
"""Returns if premises includes first thoroughfare or locality"""
|
|
21
|
+
return self.is_exception('building_name') or self.is_building_name_split_exception
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def is_building_name_split_exception(self):
|
|
25
|
+
"""Returns if building name should be split"""
|
|
26
|
+
return(
|
|
27
|
+
self.is_exception('building_name_last_word') and
|
|
28
|
+
not re.match(r'^\d+$', self.building_name_last_word)
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def building_name_last_word(self):
|
|
33
|
+
"""Returns last word of the building name"""
|
|
34
|
+
*_, last = getattr(self, 'building_name', '').split()
|
|
35
|
+
return last
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def building_name_but_last_word(self):
|
|
39
|
+
"""Returns all but last word of the building name"""
|
|
40
|
+
*first, _ = getattr(self, 'building_name', '').split()
|
|
41
|
+
return ' '.join(first)
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def name_last_word_and_thoroughfare_or_locality(self):
|
|
45
|
+
"""Returns last word of building name and first thoroughfare or locality"""
|
|
46
|
+
return self._concatenate(['building_name_last_word', 'first_thoroughfare_or_locality'])
|
paf/premises/rule011.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Rule 4"""
|
|
2
|
+
|
|
3
|
+
from .common import Common
|
|
4
|
+
|
|
5
|
+
class Rule011(Common):
|
|
6
|
+
"""Rule 4 processing"""
|
|
7
|
+
|
|
8
|
+
@property
|
|
9
|
+
def premises_rule_attrs(self):
|
|
10
|
+
"""Returns premises list"""
|
|
11
|
+
return ['building_name', 'number_and_thoroughfare_or_locality']
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def does_premises_include_first_thoroughfare_or_locality(self):
|
|
15
|
+
"""Returns if premises includes first thoroughfare or locality"""
|
|
16
|
+
return True
|
paf/premises/rule101.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Rule 5"""
|
|
2
|
+
|
|
3
|
+
from .common import Common
|
|
4
|
+
|
|
5
|
+
class Rule101(Common):
|
|
6
|
+
"""Rule 5 processing"""
|
|
7
|
+
|
|
8
|
+
@property
|
|
9
|
+
def premises_rule_attrs(self):
|
|
10
|
+
"""Returns premises list"""
|
|
11
|
+
if getattr(self, 'concatenation_indicator', '') == 'Y':
|
|
12
|
+
return ['number_sub_name_and_thoroughfare_or_locality']
|
|
13
|
+
return ['sub_building_name', 'number_and_thoroughfare_or_locality']
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def does_premises_include_first_thoroughfare_or_locality(self):
|
|
17
|
+
"""Returns if premises includes first thoroughfare or locality"""
|
|
18
|
+
return True
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def building_number_and_sub_building_name(self):
|
|
22
|
+
"""Returns building number and sub-building name"""
|
|
23
|
+
return self._concatenate(['building_number', 'sub_building_name'], '')
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def number_sub_name_and_thoroughfare_or_locality(self):
|
|
27
|
+
"""Returns building number, sub-building name and first thoroughfare or locality"""
|
|
28
|
+
return(self._concatenate([
|
|
29
|
+
'building_number_and_sub_building_name', 'first_thoroughfare_or_locality'
|
|
30
|
+
]))
|
paf/premises/rule110.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Rule 6"""
|
|
2
|
+
|
|
3
|
+
from .common import Common
|
|
4
|
+
|
|
5
|
+
class Rule110(Common):
|
|
6
|
+
"""Rule 6 processing"""
|
|
7
|
+
|
|
8
|
+
@property
|
|
9
|
+
def premises_rule_attrs(self):
|
|
10
|
+
"""Returns premises list"""
|
|
11
|
+
if self.is_exception('sub_building_name'):
|
|
12
|
+
return['sub_name_and_name']
|
|
13
|
+
if self.is_exception('building_name'):
|
|
14
|
+
return['sub_building_name', 'name_and_thoroughfare_or_locality']
|
|
15
|
+
return ['sub_building_name', 'building_name']
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def does_premises_include_first_thoroughfare_or_locality(self):
|
|
19
|
+
"""Returns if premises includes first thoroughfare or locality"""
|
|
20
|
+
return (not self.is_exception('sub_building_name')) and self.is_exception('building_name')
|
paf/premises/rule111.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Rule 7"""
|
|
2
|
+
|
|
3
|
+
from .common import Common
|
|
4
|
+
|
|
5
|
+
class Rule111(Common):
|
|
6
|
+
"""Rule 7 processing"""
|
|
7
|
+
|
|
8
|
+
@property
|
|
9
|
+
def premises_rule_attrs(self):
|
|
10
|
+
"""Returns premises list"""
|
|
11
|
+
if self.is_exception('sub_building_name'):
|
|
12
|
+
return['sub_name_and_name', 'number_and_thoroughfare_or_locality']
|
|
13
|
+
return ['sub_building_name', 'building_name', 'number_and_thoroughfare_or_locality']
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def does_premises_include_first_thoroughfare_or_locality(self):
|
|
17
|
+
"""Returns if premises includes first thoroughfare or locality"""
|
|
18
|
+
return True
|
paf/premises_extender.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Premises Extender Mixin"""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from .attribute import AttributeMixin
|
|
5
|
+
from .premises.rule000 import Rule000 # pylint: disable=unused-import
|
|
6
|
+
from .premises.rule001 import Rule001 # pylint: disable=unused-import
|
|
7
|
+
from .premises.rule010 import Rule010 # pylint: disable=unused-import
|
|
8
|
+
from .premises.rule011 import Rule011 # pylint: disable=unused-import
|
|
9
|
+
from .premises.rule101 import Rule101 # pylint: disable=unused-import
|
|
10
|
+
from .premises.rule110 import Rule110 # pylint: disable=unused-import
|
|
11
|
+
from .premises.rule111 import Rule111 # pylint: disable=unused-import
|
|
12
|
+
|
|
13
|
+
class PremisesExtenderMixin(AttributeMixin):
|
|
14
|
+
"""Dynamic Premises processing"""
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def premises_rule(self):
|
|
18
|
+
"""Returns premises rule class"""
|
|
19
|
+
rule = ''.join(['0' if self.is_empty(k) else '1' for k in self.__class__.premises_attrs])
|
|
20
|
+
return getattr(sys.modules[__name__], 'Rule' + rule)
|
|
21
|
+
|
|
22
|
+
def extend_premises(self):
|
|
23
|
+
"""Dynamically extends instance with appropriate premises rule"""
|
|
24
|
+
base_cls = self.__class__
|
|
25
|
+
self.__class__ = type(base_cls.__name__, (base_cls, self.premises_rule), {})
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Thoroughfare and Locality Mixin"""
|
|
2
|
+
|
|
3
|
+
from .premises_extender import PremisesExtenderMixin
|
|
4
|
+
|
|
5
|
+
class ThoroughfareLocalityMixin(PremisesExtenderMixin):
|
|
6
|
+
"""Thoroughfare and locality processing"""
|
|
7
|
+
|
|
8
|
+
@classmethod
|
|
9
|
+
@property
|
|
10
|
+
def thoroughfare_and_locality_attrs(cls):
|
|
11
|
+
"""Returns Paf address line attributes"""
|
|
12
|
+
return ['dependent_thoroughfare', 'thoroughfare'] + cls.locality_attrs
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def thoroughfares_and_localities(self):
|
|
16
|
+
"""Returns thoroughfares and localities list"""
|
|
17
|
+
attrs = self.__class__.thoroughfare_and_locality_attrs
|
|
18
|
+
return [getattr(self, k) for k in attrs if not self.is_used_or_empty(k)]
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def dependent_thoroughfare(self):
|
|
22
|
+
"""Returns dependent thoroughfare"""
|
|
23
|
+
return self._concatenate(self.__class__.dependent_thoroughfare_attrs)
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def thoroughfare(self):
|
|
27
|
+
"""Returns thoroughfare"""
|
|
28
|
+
return self._concatenate(self.__class__.thoroughfare_attrs)
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def first_thoroughfare_or_locality_attr(self):
|
|
32
|
+
"""Returns name of first populated thoroughfare or locality attribute"""
|
|
33
|
+
for k in self.__class__.thoroughfare_and_locality_attrs:
|
|
34
|
+
if not self.is_empty(k):
|
|
35
|
+
return k
|
|
36
|
+
return None
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def first_thoroughfare_or_locality(self):
|
|
40
|
+
"""Returns first populated thoroughfare or locality value"""
|
|
41
|
+
attr = self.first_thoroughfare_or_locality_attr
|
|
42
|
+
return getattr(self, attr) if attr is not None else ''
|
|
43
|
+
|
|
44
|
+
def is_used_or_empty(self, attr):
|
|
45
|
+
"""Returns if attribute value is empty or has already been used"""
|
|
46
|
+
if self.is_empty(attr):
|
|
47
|
+
return True
|
|
48
|
+
return(
|
|
49
|
+
attr == self.first_thoroughfare_or_locality_attr and
|
|
50
|
+
self.does_premises_include_first_thoroughfare_or_locality
|
|
51
|
+
)
|
paf/version.py
ADDED