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

zopefoundation / zope.i18n / 16399678496

27 Sep 2024 06:55AM UTC coverage: 98.997% (-0.02%) from 99.018%
16399678496

push

github

icemac
Back to development: 5.3

747 of 784 branches covered (95.28%)

Branch coverage included in aggregate %.

3203 of 3206 relevant lines covered (99.91%)

1.0 hits per line

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

100.0
/src/zope/i18n/interfaces/locales.py
1
##############################################################################
2
#
3
# Copyright (c) 2001, 2002 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
"""Interfaces related to Locales
15
"""
16
import datetime
1✔
17
import re
1✔
18

19
from zope.interface import Attribute
1✔
20
from zope.interface import Interface
1✔
21
from zope.schema import Bool
1✔
22
from zope.schema import Choice
1✔
23
from zope.schema import Date
1✔
24
from zope.schema import Dict
1✔
25
from zope.schema import Field
1✔
26
from zope.schema import Int
1✔
27
from zope.schema import List
1✔
28
from zope.schema import Text
1✔
29
from zope.schema import TextLine
1✔
30
from zope.schema import Tuple
1✔
31

32

33
class ILocaleProvider(Interface):
1✔
34
    """This interface is our connection to the Zope 3 service. From it
35
    we can request various Locale objects that can perform all sorts of
36
    fancy operations.
37

38
    This service will be singelton global service, since it doe not make much
39
    sense to have many locale facilities, especially since this one will be so
40
    complete, since we will the ICU XML Files as data.  """
41

42
    def loadLocale(language=None, country=None, variant=None):
1✔
43
        """Load the locale with the specs that are given by the arguments of
44
        the method. Note that the LocaleProvider must know where to get the
45
        locales from."""
46

47
    def getLocale(language=None, country=None, variant=None):
1✔
48
        """Get the Locale object for a particular language, country and
49
        variant."""
50

51

52
class ILocaleIdentity(Interface):
1✔
53
    """Identity information class for ILocale objects.
54

55
    Three pieces of information are required to identify a locale:
56

57
      o language -- Language in which all of the locale text information are
58
        returned.
59

60
      o script -- Script in which all of the locale text information are
61
        returned.
62

63
      o territory -- Territory for which the locale's information are
64
        appropriate. None means all territories in which language is spoken.
65

66
      o variant -- Sometimes there are regional or historical differences even
67
        in a certain country. For these cases we use the variant field. A good
68
        example is the time before the Euro in Germany for example. Therefore
69
        a valid variant would be 'PREEURO'.
70

71
    Note that all of these attributes are read-only once they are set (usually
72
    done in the constructor)!
73

74
    This object is also used to uniquely identify a locale.
75
    """
76

77
    language = TextLine(
1✔
78
        title="Language Type",
79
        description="The language for which a locale is applicable.",
80
        constraint=re.compile(r'[a-z]{2}').match,
81
        required=True,
82
        readonly=True)
83

84
    script = TextLine(
1✔
85
        title="Script Type",
86
        description=("""The script for which the language/locale is
87
                       applicable."""),
88
        constraint=re.compile(r'[a-z]*').match)
89

90
    territory = TextLine(
1✔
91
        title="Territory Type",
92
        description="The territory for which a locale is applicable.",
93
        constraint=re.compile(r'[A-Z]{2}').match,
94
        required=True,
95
        readonly=True)
96

97
    variant = TextLine(
1✔
98
        title="Variant Type",
99
        description="The variant for which a locale is applicable.",
100
        constraint=re.compile(r'[a-zA-Z]*').match,
101
        required=True,
102
        readonly=True)
103

104
    version = Field(
1✔
105
        title="Locale Version",
106
        description="The value of this field is an ILocaleVersion object.",
107
        readonly=True)
108

109
    def __repr__(self):
1✔
110
        """Defines the representation of the id, which should be a compact
111
        string that references the language, country and variant."""
112

113

114
class ILocaleVersion(Interface):
1✔
115
    """Represents the version of a locale.
116

117
    The locale version is part of the ILocaleIdentity object.
118
    """
119

120
    number = TextLine(
1✔
121
        title="Version Number",
122
        description="The version number of the locale.",
123
        constraint=re.compile(r'^([0-9].)*[0-9]$').match,
124
        required=True,
125
        readonly=True)
126

127
    generationDate = Date(
1✔
128
        title="Generation Date",
129
        description="Specifies the creation date of the locale.",
130
        constraint=lambda date: date < datetime.datetime.now(),
131
        readonly=True)
132

133
    notes = Text(
1✔
134
        title="Notes",
135
        description="Some release notes for the version of this locale.",
136
        readonly=True)
137

138

139
class ILocaleDisplayNames(Interface):
1✔
140
    """Localized Names of common text strings.
141

142
    This object contains localized strings for many terms, including
143
    language, script and territory names. But also keys and types used
144
    throughout the locale object are localized here.
145
    """
146

147
    languages = Dict(
1✔
148
        title="Language type to translated name",
149
        key_type=TextLine(title="Language Type"),
150
        value_type=TextLine(title="Language Name"))
151

152
    scripts = Dict(
1✔
153
        title="Script type to script name",
154
        key_type=TextLine(title="Script Type"),
155
        value_type=TextLine(title="Script Name"))
156

157
    territories = Dict(
1✔
158
        title="Territory type to translated territory name",
159
        key_type=TextLine(title="Territory Type"),
160
        value_type=TextLine(title="Territory Name"))
161

162
    variants = Dict(
1✔
163
        title="Variant type to name",
164
        key_type=TextLine(title="Variant Type"),
165
        value_type=TextLine(title="Variant Name"))
166

167
    keys = Dict(
1✔
168
        title="Key type to name",
169
        key_type=TextLine(title="Key Type"),
170
        value_type=TextLine(title="Key Name"))
171

172
    types = Dict(
1✔
173
        title="Type type and key to localized name",
174
        key_type=Tuple(title="Type Type and Key"),
175
        value_type=TextLine(title="Type Name"))
176

177

178
class ILocaleTimeZone(Interface):
1✔
179
    """Represents and defines various timezone information. It mainly manages
180
    all the various names for a timezone and the cities contained in it.
181

182
    Important: ILocaleTimeZone objects are not intended to provide
183
    implementations for the standard datetime module timezone support. They
184
    are merily used for Locale support.
185
    """
186

187
    type = TextLine(
1✔
188
        title="Time Zone Type",
189
        description="Standard name of the timezone for unique referencing.",
190
        required=True,
191
        readonly=True)
192

193
    cities = List(
1✔
194
        title="Cities",
195
        description="Cities in Timezone",
196
        value_type=TextLine(title="City Name"),
197
        required=True,
198
        readonly=True)
199

200
    names = Dict(
1✔
201
        title="Time Zone Names",
202
        description="Various names of the timezone.",
203
        key_type=Choice(
204
            title="Time Zone Name Type",
205
            values=("generic", "standard", "daylight")),
206
        value_type=Tuple(title="Time Zone Name and Abbreviation",
207
                         min_length=2, max_length=2),
208
        required=True,
209
        readonly=True)
210

211

212
class ILocaleFormat(Interface):
1✔
213
    """Specifies a format for a particular type of data."""
214

215
    type = TextLine(
1✔
216
        title="Format Type",
217
        description="The name of the format",
218
        required=False,
219
        readonly=True)
220

221
    displayName = TextLine(
1✔
222
        title="Display Name",
223
        description="Name of the calendar, for example 'gregorian'.",
224
        required=False,
225
        readonly=True)
226

227
    pattern = TextLine(
1✔
228
        title="Format Pattern",
229
        description="The pattern that is used to format the object.",
230
        required=True,
231
        readonly=True)
232

233

234
class ILocaleFormatLength(Interface):
1✔
235
    """The format length describes a class of formats."""
236

237
    type = Choice(
1✔
238
        title="Format Length Type",
239
        description="Name of the format length",
240
        values=("full", "long", "medium", "short")
241
    )
242

243
    default = TextLine(
1✔
244
        title="Default Format",
245
        description="The name of the defaulkt format.")
246

247
    formats = Dict(
1✔
248
        title="Formats",
249
        description="Maps format types to format objects",
250
        key_type=TextLine(title="Format Type"),
251
        value_type=Field(
252
            title="Format Object",
253
            description="Values are ILocaleFormat objects."),
254
        required=True,
255
        readonly=True)
256

257

258
class ILocaleMonthContext(Interface):
1✔
259
    """Specifices a usage context for month names"""
260

261
    type = TextLine(
1✔
262
        title="Month context type",
263
        description="Name of the month context, format or stand-alone.")
264

265
    defaultWidth = TextLine(
1✔
266
        title="Default month name width",
267
        default="wide")
268

269
    months = Dict(
1✔
270
        title="Month Names",
271
        description=("A mapping of month name widths to a mapping of"
272
                     "corresponding month names."),
273
        key_type=Choice(
274
            title="Width type",
275
            values=("wide", "abbreviated", "narrow")),
276
        value_type=Dict(
277
            title="Month name",
278
            key_type=Int(title="Type", min=1, max=12),
279
            value_type=TextLine(title="Month Name"))
280
    )
281

282

283
class ILocaleDayContext(Interface):
1✔
284
    """Specifices a usage context for days names"""
285

286
    type = TextLine(
1✔
287
        title="Day context type",
288
        description="Name of the day context, format or stand-alone.")
289

290
    defaultWidth = TextLine(
1✔
291
        title="Default day name width",
292
        default="wide")
293

294
    days = Dict(
1✔
295
        title="Day Names",
296
        description=("A mapping of day name widths to a mapping of"
297
                     "corresponding day names."),
298
        key_type=Choice(
299
            title="Width type",
300
            values=("wide", "abbreviated", "narrow")),
301
        value_type=Dict(
302
            title="Day name",
303
            key_type=Choice(
304
                title="Type",
305
                values=("sun", "mon", "tue", "wed",
306
                        "thu", "fri", "sat")),
307
            value_type=TextLine(title="Day Name"))
308
    )
309

310

311
class ILocaleCalendar(Interface):
1✔
312
    """There is a massive amount of information contained in the calendar,
313
    which made it attractive to be added."""
314

315
    type = TextLine(
1✔
316
        title="Calendar Type",
317
        description="Name of the calendar, for example 'gregorian'.")
318

319
    defaultMonthContext = TextLine(
1✔
320
        title="Default month context",
321
        default="format")
322

323
    monthContexts = Dict(
1✔
324
        title="Month Contexts",
325
        description=("A mapping of month context types to "
326
                     "ILocaleMonthContext objects"),
327
        key_type=Choice(title="Type",
328
                        values=("format", "stand-alone")),
329
        value_type=Field(title="ILocaleMonthContext object"))
330

331
    # BBB: leftover from CLDR 1.0
332
    months = Dict(
1✔
333
        title="Month Names",
334
        description="A mapping of all month names and abbreviations",
335
        key_type=Int(title="Type", min=1, max=12),
336
        value_type=Tuple(title="Month Name and Abbreviation",
337
                         min_length=2, max_length=2))
338

339
    defaultDayContext = TextLine(
1✔
340
        title="Default day context",
341
        default="format")
342

343
    dayContexts = Dict(
1✔
344
        title="Day Contexts",
345
        description=("A mapping of day context types to "
346
                     "ILocaleDayContext objects"),
347
        key_type=Choice(title="Type",
348
                        values=("format", "stand-alone")),
349
        value_type=Field(title="ILocaleDayContext object"))
350

351
    # BBB: leftover from CLDR 1.0
352
    days = Dict(
1✔
353
        title="Weekdays Names",
354
        description="A mapping of all month names and abbreviations",
355
        key_type=Choice(title="Type",
356
                        values=("sun", "mon", "tue", "wed",
357
                                "thu", "fri", "sat")),
358
        value_type=Tuple(title="Weekdays Name and Abbreviation",
359
                         min_length=2, max_length=2))
360

361
    week = Dict(
1✔
362
        title="Week Information",
363
        description="Contains various week information",
364
        key_type=Choice(
365
            title="Type",
366
            description=("""
367
            Varies Week information:
368

369
              - 'minDays' is just an integer between 1 and 7.
370

371
              - 'firstDay' specifies the first day of the week by integer.
372

373
              - The 'weekendStart' and 'weekendEnd' are tuples of the form
374
                (weekDayNumber, datetime.time)
375
            """),
376
            values=("minDays", "firstDay",
377
                    "weekendStart", "weekendEnd")))
378

379
    am = TextLine(title="AM String")
1✔
380

381
    pm = TextLine(title="PM String")
1✔
382

383
    eras = Dict(
1✔
384
        title="Era Names",
385
        key_type=Int(title="Type", min=0),
386
        value_type=Tuple(title="Era Name and Abbreviation",
387
                         min_length=2, max_length=2))
388

389
    defaultDateFormat = TextLine(title="Default Date Format Type")
1✔
390

391
    dateFormats = Dict(
1✔
392
        title="Date Formats",
393
        description="Contains various Date Formats.",
394
        key_type=Choice(
395
            title="Type",
396
            description="Name of the format length",
397
            values=("full", "long", "medium", "short")),
398
        value_type=Field(title="ILocaleFormatLength object"))
399

400
    defaultTimeFormat = TextLine(title="Default Time Format Type")
1✔
401

402
    timeFormats = Dict(
1✔
403
        title="Time Formats",
404
        description="Contains various Time Formats.",
405
        key_type=Choice(
406
            title="Type",
407
            description="Name of the format length",
408
            values=("full", "long", "medium", "short")),
409
        value_type=Field(title="ILocaleFormatLength object"))
410

411
    defaultDateTimeFormat = TextLine(title="Default Date-Time Format Type")
1✔
412

413
    dateTimeFormats = Dict(
1✔
414
        title="Date-Time Formats",
415
        description="Contains various Date-Time Formats.",
416
        key_type=Choice(
417
            title="Type",
418
            description="Name of the format length",
419
            values=("full", "long", "medium", "short")),
420
        value_type=Field(title="ILocaleFormatLength object"))
421

422
    def getMonthNames():
1✔
423
        """Return a list of month names."""
424

425
    def getMonthTypeFromName(name):
1✔
426
        """Return the type of the month with the right name."""
427

428
    def getMonthAbbreviations():
1✔
429
        """Return a list of month abbreviations."""
430

431
    def getMonthTypeFromAbbreviation(abbr):
1✔
432
        """Return the type of the month with the right abbreviation."""
433

434
    def getDayNames():
1✔
435
        """Return a list of weekday names."""
436

437
    def getDayTypeFromName(name):
1✔
438
        """Return the id of the weekday with the right name."""
439

440
    def getDayAbbr():
1✔
441
        """Return a list of weekday abbreviations."""
442

443
    def getDayTypeFromAbbr(abbr):
1✔
444
        """Return the id of the weekday with the right abbr."""
445

446
    def isWeekend(datetime):
1✔
447
        """Determines whether a the argument lies in a weekend."""
448

449
    def getFirstDayName():
1✔
450
        """Return the the type of the first day in the week."""
451

452

453
class ILocaleDates(Interface):
1✔
454
    """This object contains various data about dates, times and time zones."""
455

456
    localizedPatternChars = TextLine(
1✔
457
        title="Localized Pattern Characters",
458
        description="Localized pattern characters used in dates and times")
459

460
    calendars = Dict(
1✔
461
        title="Calendar type to ILocaleCalendar",
462
        key_type=Choice(
463
            title="Calendar Type",
464
            values=("gregorian",
465
                    "arabic",
466
                    "chinese",
467
                    "civil-arabic",
468
                    "hebrew",
469
                    "japanese",
470
                    "thai-buddhist")),
471
        value_type=Field(title="Calendar",
472
                         description="This is a ILocaleCalendar object."))
473

474
    timezones = Dict(
1✔
475
        title="Time zone type to ILocaleTimezone",
476
        key_type=TextLine(title="Time Zone type"),
477
        value_type=Field(title="Time Zone",
478
                         description="This is a ILocaleTimeZone object."))
479

480
    def getFormatter(category, length=None, name=None, calendar="gregorian"):
1✔
481
        """Get a date/time formatter.
482

483
        `category` must be one of 'date', 'dateTime', 'time'.
484

485
        The 'length' specifies the output length of the value. The allowed
486
        values are: 'short', 'medium', 'long' and 'full'. If no length was
487
        specified, the default length is chosen.
488
        """
489

490

491
class ILocaleCurrency(Interface):
1✔
492
    """Defines a particular currency."""
493

494
    type = TextLine(title="Type")
1✔
495

496
    symbol = TextLine(title="Symbol")
1✔
497

498
    displayName = TextLine(title="Official Name")
1✔
499

500
    symbolChoice = Bool(title="Symbol Choice")
1✔
501

502

503
class ILocaleNumbers(Interface):
1✔
504
    """This object contains various data about numbers and currencies."""
505

506
    symbols = Dict(
1✔
507
        title="Number Symbols",
508
        key_type=Choice(
509
            title="Format Name",
510
            values=("decimal", "group", "list", "percentSign",
511
                    "nativeZeroDigit", "patternDigit", "plusSign",
512
                    "minusSign", "exponential", "perMille",
513
                    "infinity", "nan")),
514
        value_type=TextLine(title="Symbol"))
515

516
    defaultDecimalFormat = TextLine(title="Default Decimal Format Type")
1✔
517

518
    decimalFormats = Dict(
1✔
519
        title="Decimal Formats",
520
        description="Contains various Decimal Formats.",
521
        key_type=Choice(
522
            title="Type",
523
            description="Name of the format length",
524
            values=("full", "long", "medium", "short")),
525
        value_type=Field(title="ILocaleFormatLength object"))
526

527
    defaultScientificFormat = TextLine(title="Default Scientific Format Type")
1✔
528

529
    scientificFormats = Dict(
1✔
530
        title="Scientific Formats",
531
        description="Contains various Scientific Formats.",
532
        key_type=Choice(
533
            title="Type",
534
            description="Name of the format length",
535
            values=("full", "long", "medium", "short")),
536
        value_type=Field(title="ILocaleFormatLength object"))
537

538
    defaultPercentFormat = TextLine(title="Default Percent Format Type")
1✔
539

540
    percentFormats = Dict(
1✔
541
        title="Percent Formats",
542
        description="Contains various Percent Formats.",
543
        key_type=Choice(
544
            title="Type",
545
            description="Name of the format length",
546
            values=("full", "long", "medium", "short")),
547
        value_type=Field(title="ILocaleFormatLength object"))
548

549
    defaultCurrencyFormat = TextLine(title="Default Currency Format Type")
1✔
550

551
    currencyFormats = Dict(
1✔
552
        title="Currency Formats",
553
        description="Contains various Currency Formats.",
554
        key_type=Choice(
555
            title="Type",
556
            description="Name of the format length",
557
            values=("full", "long", "medium", "short")),
558
        value_type=Field(title="ILocaleFormatLength object"))
559

560
    currencies = Dict(
1✔
561
        title="Currencies",
562
        description="Contains various Currency data.",
563
        key_type=TextLine(
564
            title="Type",
565
            description="Name of the format length"),
566
        value_type=Field(title="ILocaleCurrency object"))
567

568
    def getFormatter(category, length=None, name=""):
1✔
569
        """Get the NumberFormat based on the category, length and name of the
570
        format.
571

572
        The 'category' specifies the type of number format you would like to
573
        have. The available options are: 'decimal', 'percent', 'scientific',
574
        'currency'.
575

576
        The 'length' specifies the output length of the number. The allowed
577
        values are: 'short', 'medium', 'long' and 'full'. If no length was
578
        specified, the default length is chosen.
579

580
        Every length can have actually several formats. In this case these
581
        formats are named and you can specify the name here. If no name was
582
        specified, the first unnamed format is chosen.
583
        """
584

585
    def getDefaultCurrency():
1✔
586
        """Get the default currency."""
587

588

589
_orientations = ["left-to-right", "right-to-left",
1✔
590
                 "top-to-bottom", "bottom-to-top"]
591

592

593
class ILocaleOrientation(Interface):
1✔
594
    """Information about the orientation of text."""
595

596
    characters = Choice(
1✔
597
        title="Orientation of characters",
598
        values=_orientations,
599
        default="left-to-right"
600
    )
601

602
    lines = Choice(
1✔
603
        title="Orientation of characters",
604
        values=_orientations,
605
        default="top-to-bottom"
606
    )
607

608

609
class ILocale(Interface):
1✔
610
    """This class contains all important information about the locale.
611

612
    Usually a Locale is identified using a specific language, country and
613
    variant.  However, the country and variant are optional, so that a lookup
614
    hierarchy develops.  It is easy to recognize that a locale that is missing
615
    the variant is more general applicable than the one with the variant.
616
    Therefore, if a specific Locale does not contain the required information,
617
    it should look one level higher.  There will be a root locale that
618
    specifies none of the above identifiers.
619
    """
620

621
    id = Field(
1✔
622
        title="Locale identity",
623
        description="ILocaleIdentity object identifying the locale.",
624
        required=True,
625
        readonly=True)
626

627
    displayNames = Field(
1✔
628
        title="Display Names",
629
        description=("""ILocaleDisplayNames object that contains localized
630
                        names."""))
631

632
    dates = Field(
1✔
633
        title="Dates",
634
        description="ILocaleDates object that contains date/time data.")
635

636
    numbers = Field(
1✔
637
        title="Numbers",
638
        description="ILocaleNumbers object that contains number data.")
639

640
    orientation = Field(
1✔
641
        title="Orientation",
642
        description="ILocaleOrientation with text orientation info.")
643

644
    delimiters = Dict(
1✔
645
        title="Delimiters",
646
        description="Contains various Currency data.",
647
        key_type=Choice(
648
            title="Delimiter Type",
649
            description="Delimiter name.",
650
            values=("quotationStart",
651
                    "quotationEnd",
652
                    "alternateQuotationStart",
653
                    "alternateQuotationEnd")),
654
        value_type=Field(title="Delimiter symbol"))
655

656
    def getLocaleID():
1✔
657
        """Return a locale id as specified in the LDML specification"""
658

659

660
class ILocaleInheritance(Interface):
1✔
661
    """Locale inheritance support.
662

663
    Locale-related objects implementing this interface are able to ask for its
664
    inherited self. For example, 'en_US.dates.monthNames' can call on itself
665
    'getInheritedSelf()' and get the value for 'en.dates.monthNames'.
666
    """
667

668
    __parent__ = Attribute("The parent in the location hierarchy")
1✔
669

670
    __name__ = TextLine(
1✔
671
        title="The name within the parent",
672
        description=("""The parent can be traversed with this name to get
673
                       the object."""))
674

675
    def getInheritedSelf():
1✔
676
        """Return itself but in the next higher up Locale."""
677

678

679
class IAttributeInheritance(ILocaleInheritance):
1✔
680
    """Provides inheritance properties for attributes"""
681

682
    def __setattr__(name, value):
1✔
683
        """Set a new attribute on the object.
684

685
        When a value is set on any inheritance-aware object and the value
686
        also implements ILocaleInheritance, then we need to set the
687
        '__parent__' and '__name__' attribute on the value.
688
        """
689

690
    def __getattribute__(name):
1✔
691
        """Return the value of the attribute with the specified name.
692

693
        If an attribute is not found or is None, the next higher up Locale
694
        object is consulted."""
695

696

697
class IDictionaryInheritance(ILocaleInheritance):
1✔
698
    """Provides inheritance properties for dictionary keys"""
699

700
    def __setitem__(key, value):
1✔
701
        """Set a new item on the object.
702

703
        Here we assume that the value does not require any inheritance, so
704
        that we do not set '__parent__' or '__name__' on the value.
705
        """
706

707
    def __getitem__(key):
1✔
708
        """Return the value of the item with the specified name.
709

710
        If an key is not found or is None, the next higher up Locale
711
        object is consulted.
712
        """
713

714

715
class ICollator(Interface):
1✔
716
    """Provide support for collating text strings
717

718
    This interface will typically be provided by adapting a locale.
719
    """
720

721
    def key(text):
1✔
722
        """Return a collation key for the given text.
723
        """
724

725
    def cmp(text1, text2):
1✔
726
        """Compare two text strings.
727

728
        The return value is negative if text1 < text2, 0 is they are
729
        equal, and positive if text1 > text2.
730
        """
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