Repository: crsmithdev/arrow
Pull request #797 (2020-06-04 16:29:52)

Add Swahili Locale
## Pull Request Checklist

Thank you for taking the time to improve Arrow! Before submitting your pull request, please check all *appropriate* boxes:

<!-- Check boxes by placing an x in the brackets: [x] -->
- [x] 🧪 Added **tests** for changed code.
- [x] 🛠️ All tests **pass** when run locally (run `tox` or `make test` to find out!).
- [x] 🧹 All linting checks **pass** when run locally (run `tox -e lint` or `make lint` to find out!).
- [ ] 📚 Updated **documentation** for changed code.
- [x] ⏩ Code is **up-to-date** with the `master` branch.

If you have *any* questions about your code changes or any of the points above, please submit your questions along with the pull request and we will try our best to help!

## Description of Changes

These changes add support for Swahili locale.


codecov-commenter: # [Codecov](https://codecov.io/gh/crsmithdev/arrow/pull/797?src=pr&el=h1) Report
> Merging [#797](https://codecov.io/gh/crsmithdev/arrow/pull/797?src=pr&el=desc) into [master](https://codecov.io/gh/crsmithdev/arrow/commit/e7a567628092f16189b0f9f5247d67fbff899ce5&el=desc) will **not change** coverage.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/crsmithdev/arrow/pull/797/graphs/tree.svg?width=650&height=150&src=pr&token=4EkGnFsIGn)](https://codecov.io/gh/crsmithdev/arrow/pull/797?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##            master      #797   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           10        10           
  Lines         1713      1724   +11     
  Branches       295       295           
=========================================
+ Hits          1713      1724   +11     
```


| [Impacted Files](https://codecov.io/gh/crsmithdev/arrow/pull/797?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [arrow/locales.py](https://codecov.io/gh/crsmithdev/arrow/pull/797/diff?src=pr&el=tree#diff-YXJyb3cvbG9jYWxlcy5weQ==) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/crsmithdev/arrow/pull/797?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/crsmithdev/arrow/pull/797?src=pr&el=footer). Last update [e7a5676...eb344ea](https://codecov.io/gh/crsmithdev/arrow/pull/797?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

ooduor: @krisfremen sure can! I have updated with more tests.

Cheers!

Patch:
diff --git a/.github/workflows/continuous_integration.yml b/.github/workflows/continuous_integration.yml
index d299c16..24e7a9f 100644
--- a/.github/workflows/continuous_integration.yml
+++ b/.github/workflows/continuous_integration.yml
@@ -15,15 +15,13 @@ jobs:
     runs-on: ubuntu-latest
 
     steps:
-      - uses: actions/checkout@v1
+      - uses: actions/checkout@v2
       - name: Set up Python 3.8
-        uses: actions/setup-python@v1
+        uses: actions/setup-python@v2
         with:
-          python-version: 3.8
+          python-version: "3.8"
       - name: Install dependencies
-        run: |
-          pip install -U pip
-          pip install tox
+        run: pip install -U tox
       - name: Linting code
         run: tox -e lint
       - name: Linting docs
@@ -33,70 +31,61 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        python-version: [2.7, 3.5, 3.6, 3.7, 3.8]
+        python-version: ["pypy3", "2.7", "3.5", "3.6", "3.7", "3.8"]
 
     steps:
-      - uses: actions/checkout@v1
+      - uses: actions/checkout@v2
       - name: Set up Python ${{ matrix.python-version }}
-        uses: actions/setup-python@v1
+        uses: actions/setup-python@v2
         with:
           python-version: ${{ matrix.python-version }}
       - name: Install dependencies
-        run: |
-          pip install -U pip
-          pip install tox tox-gh-actions
+        run: pip install -U tox tox-gh-actions
       - name: Test with tox
         run: tox
       - name: Upload coverage to Codecov
         uses: codecov/codecov-action@v1
         with:
-          token: ${{ secrets.CODECOV_TOKEN }}
           file: .coverage
 
   MacOS:
     runs-on: macos-latest
     strategy:
       matrix:
-        python-version: [2.7, 3.5, 3.6, 3.7, 3.8]
+        python-version: ["pypy3", "2.7", "3.5", "3.6", "3.7", "3.8"]
 
     steps:
-      - uses: actions/checkout@v1
+      - uses: actions/checkout@v2
       - name: Set up Python ${{ matrix.python-version }}
-        uses: actions/setup-python@v1
+        uses: actions/setup-python@v2
         with:
           python-version: ${{ matrix.python-version }}
       - name: Install dependencies
-        run: |
-          pip install -U pip
-          pip install tox tox-gh-actions
+        run: pip install -U tox tox-gh-actions
       - name: Test with tox
         run: tox
       - name: Upload coverage to Codecov
         uses: codecov/codecov-action@v1
         with:
-          token: ${{ secrets.CODECOV_TOKEN }}
           file: .coverage
 
   Windows:
     runs-on: windows-latest
     strategy:
       matrix:
-        python-version: [2.7, 3.5, 3.6, 3.7, 3.8]
+        python-version: ["pypy3", "2.7", "3.5", "3.6", "3.7", "3.8"]
 
     steps:
-      - uses: actions/checkout@v1
+      - uses: actions/checkout@v2
       - name: Set up Python ${{ matrix.python-version }}
-        uses: actions/setup-python@v1
+        uses: actions/setup-python@v2
         with:
           python-version: ${{ matrix.python-version }}
       - name: Install dependencies
-        run: |
-          pip install -U pip
-          pip install tox tox-gh-actions
+        run: pip install -U tox tox-gh-actions
       - name: Test with tox
         run: tox
       - name: Upload coverage to Codecov
         uses: codecov/codecov-action@v1
         with:
-          token: ${{ secrets.CODECOV_TOKEN }}
           file: .coverage
diff --git a/.travis.yml b/.travis.yml
index 688c7ec..cfa2895 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -26,7 +26,7 @@ matrix:
       os: windows
       language: shell # 'language: python' is an error on Travis CI Windows
       before_install:
-        - choco install python --version 3.7.5
+        - choco install python --version 3.7.7
         - python -m pip install --upgrade pip
       env:
         - PATH=/c/Python37:/c/Python37/Scripts:$PATH
@@ -34,6 +34,9 @@ matrix:
     - name: "Python 3.8"
       python: "3.8"
       env: TOXENV=py38
+    - name: "Python 3.9"
+      python: "3.9-dev"
+      env: TOXENV=py39
     - name: "Linting"
       python: "3.7"
       env: TOXENV=lint,docs
diff --git a/Makefile b/Makefile
index 8c5c9c3..894a6ba 100644
--- a/Makefile
+++ b/Makefile
@@ -7,8 +7,9 @@ build35: PYTHON_VER = python3.5
 build36: PYTHON_VER = python3.6
 build37: PYTHON_VER = python3.7
 build38: PYTHON_VER = python3.8
+build39: PYTHON_VER = python3.9
 
-build27 build35 build36 build37 build38: clean
+build27 build35 build36 build37 build38 build39: clean
 	virtualenv venv --python=$(PYTHON_VER)
 	. venv/bin/activate; \
 	pip install -r requirements.txt; \
diff --git a/README.rst b/README.rst
index 00f3065..e31ce60 100644
--- a/README.rst
+++ b/README.rst
@@ -47,7 +47,7 @@ Features
 --------
 
 - Fully-implemented, drop-in replacement for datetime
-- Supports Python 2.7, 3.5, 3.6, 3.7 and 3.8
+- Supports Python 2.7, 3.5, 3.6, 3.7, 3.8 and 3.9
 - Timezone-aware and UTC by default
 - Provides super-simple creation options for many common input scenarios
 - :code:`shift` method with support for relative offsets, including weeks
diff --git a/arrow/locales.py b/arrow/locales.py
index e26cef5..91a9a55 100644
--- a/arrow/locales.py
+++ b/arrow/locales.py
@@ -4139,4 +4139,89 @@ class EstonianLocale(Locale):
         return form.format(abs(delta))
 
 
+class SwahiliLocale(Locale):
+
+    names = [
+        "sw",
+        "sw_ke",
+        "sw_tz",
+    ]
+
+    past = "{0} iliyopita"
+    future = "muda wa {0}"
+    and_word = "na"
+
+    timeframes = {
+        "now": "sasa hivi",
+        "second": "sekunde",
+        "seconds": "sekunde {0}",
+        "minute": "dakika moja",
+        "minutes": "dakika {0}",
+        "hour": "saa moja",
+        "hours": "saa {0}",
+        "day": "siku moja",
+        "days": "siku {0}",
+        "week": "wiki moja",
+        "weeks": "wiki {0}",
+        "month": "mwezi moja",
+        "months": "miezi {0}",
+        "year": "mwaka moja",
+        "years": "miaka {0}",
+    }
+
+    meridians = {"am": "asu", "pm": "mch", "AM": "ASU", "PM": "MCH"}
+
+    month_names = [
+        "",
+        "Januari",
+        "Februari",
+        "Machi",
+        "Aprili",
+        "Mei",
+        "Juni",
+        "Julai",
+        "Agosti",
+        "Septemba",
+        "Oktoba",
+        "Novemba",
+        "Desemba",
+    ]
+    month_abbreviations = [
+        "",
+        "Jan",
+        "Feb",
+        "Mac",
+        "Apr",
+        "Mei",
+        "Jun",
+        "Jul",
+        "Ago",
+        "Sep",
+        "Okt",
+        "Nov",
+        "Des",
+    ]
+
+    day_names = [
+        "",
+        "Jumatatu",
+        "Jumanne",
+        "Jumatano",
+        "Alhamisi",
+        "Ijumaa",
+        "Jumamosi",
+        "Jumapili",
+    ]
+    day_abbreviations = [
+        "",
+        "Jumatatu",
+        "Jumanne",
+        "Jumatano",
+        "Alhamisi",
+        "Ijumaa",
+        "Jumamosi",
+        "Jumapili",
+    ]
+
+
 _locales = _map_locales()
diff --git a/setup.py b/setup.py
index a60250a..3f6e433 100644
--- a/setup.py
+++ b/setup.py
@@ -39,8 +39,9 @@ setup(
         "Programming Language :: Python :: 3.6",
         "Programming Language :: Python :: 3.7",
         "Programming Language :: Python :: 3.8",
+        "Programming Language :: Python :: 3.9",
     ],
-    keywords="arrow date time datetime timestamp timezone",
+    keywords="arrow date time datetime timestamp timezone humanize",
     project_urls={
         "Repository": "https://github.com/crsmithdev/arrow",
         "Bug Reports": "https://github.com/crsmithdev/arrow/issues",
diff --git a/tox.ini b/tox.ini
index 9b89588..7538e71 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,14 +1,16 @@
 [tox]
-envlist = py{27,35,36,37,38},lint,docs
+envlist = py{py3,27,35,36,37,38,39},lint,docs
 skip_missing_interpreters = true
 
 [gh-actions]
 python =
+    pypy3: pypy3
     2.7: py27
     3.5: py35
     3.6: py36
     3.7: py37
     3.8: py38
+    3.9: py39
 
 # Configure testing environments
 


Test patch:
diff --git a/tests/test_locales.py b/tests/test_locales.py
index 6336889..14f5d7d 100644
--- a/tests/test_locales.py
+++ b/tests/test_locales.py
@@ -955,3 +955,41 @@ class TestChineseTWLocale:
         assert self.locale._format_timeframe("months", 11) == "11個月"
         assert self.locale._format_timeframe("year", 1) == "1年"
         assert self.locale._format_timeframe("years", 12) == "12年"
+
+
+@pytest.mark.usefixtures("lang_locale")
+class TestSwahiliLocale:
+    def test_format_timeframe(self):
+        assert self.locale._format_timeframe("now", 0) == "sasa hivi"
+        assert self.locale._format_timeframe("second", 1) == "sekunde"
+        assert self.locale._format_timeframe("seconds", 3) == "sekunde 3"
+        assert self.locale._format_timeframe("seconds", 30) == "sekunde 30"
+        assert self.locale._format_timeframe("minute", 1) == "dakika moja"
+        assert self.locale._format_timeframe("minutes", 4) == "dakika 4"
+        assert self.locale._format_timeframe("minutes", 40) == "dakika 40"
+        assert self.locale._format_timeframe("hour", 1) == "saa moja"
+        assert self.locale._format_timeframe("hours", 5) == "saa 5"
+        assert self.locale._format_timeframe("hours", 23) == "saa 23"
+        assert self.locale._format_timeframe("day", 1) == "siku moja"
+        assert self.locale._format_timeframe("days", 6) == "siku 6"
+        assert self.locale._format_timeframe("days", 12) == "siku 12"
+        assert self.locale._format_timeframe("month", 1) == "mwezi moja"
+        assert self.locale._format_timeframe("months", 7) == "miezi 7"
+        assert self.locale._format_timeframe("week", 1) == "wiki moja"
+        assert self.locale._format_timeframe("weeks", 2) == "wiki 2"
+        assert self.locale._format_timeframe("months", 11) == "miezi 11"
+        assert self.locale._format_timeframe("year", 1) == "mwaka moja"
+        assert self.locale._format_timeframe("years", 8) == "miaka 8"
+        assert self.locale._format_timeframe("years", 12) == "miaka 12"
+
+    def test_format_relative_now(self):
+        result = self.locale._format_relative("sasa hivi", "now", 0)
+        assert result == "sasa hivi"
+
+    def test_format_relative_past(self):
+        result = self.locale._format_relative("saa moja", "hour", 1)
+        assert result == "muda wa saa moja"
+
+    def test_format_relative_future(self):
+        result = self.locale._format_relative("saa moja", "hour", -1)
+        assert result == "saa moja iliyopita"