• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zopefoundation / zope.i18nmessageid / 16399665579

17 Feb 2025 07:53AM UTC coverage: 100.0%. First build
16399665579

push

github

web-flow
Update Python version support. (#63)

* Drop support for Python 3.8,
* Add preliminary support for Python 3.14.

96 of 96 branches covered (100.0%)

Branch coverage included in aggregate %.

266 of 266 relevant lines covered (100.0%)

6.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/zope/i18nmessageid/message.py
1
##############################################################################
2
#
3
# Copyright (c) 2004 Zope Foundation and Contributors.
4
# All Rights Reserved.
5
#
6
# This software is subject to the provisions of the Zope Public License,
7
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
8
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11
# FOR A PARTICULAR PURPOSE.
12
#
13
##############################################################################
14
"""I18n Messages and factories.
7✔
15
"""
16
import types
7✔
17

18

19
__docformat__ = "reStructuredText"
7✔
20
_marker = object()
7✔
21

22

23
class Message(str):
7✔
24
    """Message (Python implementation)
25

26
    This is a string used as a message.  It has a domain attribute that is
27
    its source domain, and a default attribute that is its default text to
28
    display when there is no translation.  domain may be None meaning there is
29
    no translation domain.  default may also be None, in which case the
30
    message id itself implicitly serves as the default text.
31
    """
32

33
    __slots__ = (
7✔
34
        'domain', 'default', 'mapping', '_readonly',
35
        'msgid_plural', 'default_plural', 'number')
36

37
    def __new__(cls, ustr, domain=_marker, default=_marker, mapping=_marker,
7✔
38
                msgid_plural=_marker, default_plural=_marker, number=_marker):
39
        self = str.__new__(cls, ustr)
7✔
40
        if isinstance(ustr, self.__class__):
7✔
41
            self.domain = ustr.domain
7✔
42
            self.default = ustr.default
7✔
43
            self.mapping = ustr.mapping
7✔
44
            self.msgid_plural = ustr.msgid_plural
7✔
45
            self.default_plural = ustr.default_plural
7✔
46
            self.number = ustr.number
7✔
47
        else:
48
            self.domain = None
7✔
49
            self.default = None
7✔
50
            self.mapping = None
7✔
51
            self.msgid_plural = None
7✔
52
            self.default_plural = None
7✔
53
            self.number = None
7✔
54

55
        if domain is not _marker:
7✔
56
            self.domain = domain
7✔
57
        if default is not _marker:
7✔
58
            self.default = default
7✔
59
        if mapping is None:
7✔
60
            self.mapping = None
7✔
61
        elif mapping is not _marker:
7✔
62
            self.mapping = types.MappingProxyType(mapping)
7✔
63
        if msgid_plural is not _marker:
7✔
64
            self.msgid_plural = msgid_plural
7✔
65
        if default_plural is not _marker:
7✔
66
            self.default_plural = default_plural
7✔
67
        if number is not _marker:
7✔
68
            self.number = number
7✔
69

70
        if self.number is not None and not isinstance(
7✔
71
                self.number, (int, float)):
72
            raise TypeError('`number` should be an integer or a float')
7✔
73

74
        self._readonly = True
7✔
75
        return self
7✔
76

77
    def __setattr__(self, key, value):
7✔
78
        """Message is immutable
79

80
        It cannot be changed once the message id is created.
81
        """
82
        if getattr(self, '_readonly', False):
7✔
83
            raise AttributeError('readonly attribute')
7✔
84
        else:
85
            return str.__setattr__(self, key, value)
7✔
86

87
    def __getstate__(self):
7✔
88
        # types.MappingProxyType is not picklable
89
        mapping = None if self.mapping is None else dict(self.mapping)
7✔
90
        return (
7✔
91
            str(self),
92
            self.domain,
93
            self.default,
94
            mapping,
95
            self.msgid_plural,
96
            self.default_plural,
97
            self.number,
98
        )
99

100
    def __reduce__(self):
7✔
101
        return self.__class__, self.__getstate__()
7✔
102

103

104
# Name the fallback Python implementation to make it easier to test.
105
pyMessage = Message
7✔
106

107

108
try:
7✔
109
    from ._zope_i18nmessageid_message import Message
7✔
110
except ModuleNotFoundError:  # pragma: no cover
111
    pass
112

113

114
class MessageFactory:
7✔
115
    """Factory for creating i18n messages."""
116

117
    def __init__(self, domain):
7✔
118
        self._domain = domain
7✔
119

120
    def __call__(self, ustr, default=None, mapping=None,
7✔
121
                 msgid_plural=None, default_plural=None, number=None):
122
        return Message(ustr, self._domain, default, mapping,
7✔
123
                       msgid_plural, default_plural, number)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc