Skip to content

Commit 72e83ef

Browse files
authored
Merge branch 'master' into 765-print_structure-nested-tableset
2 parents cfdc90f + 8eee14a commit 72e83ef

34 files changed

+140
-67
lines changed

.github/dependabot.yml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "github-actions"
4+
directory: "/"
5+
schedule:
6+
interval: "daily"

.github/workflows/ci.yml

+3-8
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,7 @@ jobs:
77
strategy:
88
matrix:
99
os: [macos-latest, windows-latest, ubuntu-latest]
10-
python-version: [3.7, 3.8, 3.9, '3.10', '3.11', pypy-3.7]
11-
exclude:
12-
- os: windows-latest
13-
python-version: 3.7
14-
- os: windows-latest
15-
python-version: pypy-3.7
10+
python-version: [3.8, 3.9, '3.10', '3.11', '3.12', pypy-3.9]
1611
steps:
1712
- if: matrix.os == 'ubuntu-latest'
1813
name: Install UTF-8 locales and lxml requirements
@@ -22,8 +17,8 @@ jobs:
2217
sudo locale-gen en_US.UTF-8
2318
sudo locale-gen ko_KR.UTF-8
2419
sudo update-locale
25-
- uses: actions/checkout@v3
26-
- uses: actions/setup-python@v4
20+
- uses: actions/checkout@v4
21+
- uses: actions/setup-python@v5
2722
with:
2823
python-version: ${{ matrix.python-version }}
2924
cache: pip

.github/workflows/lint.yml

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
name: Lint
22
on: [push, pull_request]
3-
env:
4-
BASEDIR: https://raw.githubusercontent.com/open-contracting/standard-maintenance-scripts/main
53
jobs:
64
build:
75
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
86
runs-on: ubuntu-latest
97
steps:
10-
- uses: actions/checkout@v3
11-
- uses: actions/setup-python@v4
8+
- uses: actions/checkout@v4
9+
- uses: actions/setup-python@v5
1210
with:
1311
python-version: '3.10'
1412
cache: pip

.github/workflows/pypi.yml

+4-5
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,20 @@ on: push
33
jobs:
44
build:
55
runs-on: ubuntu-latest
6+
permissions:
7+
id-token: write
68
steps:
7-
- uses: actions/checkout@v3
8-
- uses: actions/setup-python@v4
9+
- uses: actions/checkout@v4
10+
- uses: actions/setup-python@v5
911
with:
1012
python-version: '3.10'
1113
- run: pip install --upgrade build
1214
- run: python -m build --sdist --wheel
1315
- name: Publish to TestPyPI
1416
uses: pypa/gh-action-pypi-publish@release/v1
1517
with:
16-
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
1718
repository-url: https://test.pypi.org/legacy/
1819
skip-existing: true
1920
- name: Publish to PyPI
2021
if: startsWith(github.ref, 'refs/tags')
2122
uses: pypa/gh-action-pypi-publish@release/v1
22-
with:
23-
password: ${{ secrets.PYPI_API_TOKEN }}

AUTHORS.rst

+2
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,5 @@ agate is made by a community. The following individuals have contributed code, d
4646
* `mathdesc <https://github.com/mathdesc>`_
4747
* `Tim Gates <https://github.com/timgates42>`_
4848
* `castorf <https://github.com/castorf>`_
49+
* `Julien Enselme <https://github.com/Jenselme>`__
50+

CHANGELOG.rst

+28-13
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,38 @@
1-
Unreleased
2-
----------
1+
1.11.0 - April 27. 2024
2+
-----------------------
3+
4+
* fix: Fix :meth:`.TableSet.print_structure` for nested tablesets. (#765)
5+
6+
1.9.1 - December 21, 2023
7+
-------------------------
8+
9+
* Add Babel 2.14 support.
10+
11+
1.9.0 - October 17, 2023
12+
------------------------
13+
14+
* feat: Add a ``text_truncation_chars`` configuration for values that exceed ``max_column_width`` in :meth:`.Table.print_table` and :meth:`.Table.print_html`.
15+
* feat: Add a ``number_truncation_chars`` configuration for values that exceed ``max_precision`` in :meth:`.Table.print_table` and :meth:`.Table.print_html`.
16+
17+
1.8.0 - October 10, 2023
18+
------------------------
319

420
* feat: Lowercase the ``null_values`` provided to individual data types, since all comparisons to ``null_values`` are case-insensitive. (#770)
521
* feat: :class:`.Mean` works with :class:`.TimeDelta`. (#761)
6-
* fix: Fix :meth:`.TableSet.print_structure` for nested tablesets. (#765)
22+
* Switch from ``pytz`` to ``ZoneInfo``.
23+
* Add Python 3.12 support.
24+
* Drop Python 3.7 support (end-of-life was June 27, 2023).
725

8-
1.7.1 - Jan 4, 2023
9-
-------------------
26+
1.7.1 - January 4, 2023
27+
-----------------------
1028

1129
* Allow parsedatetime 2.6.
1230

13-
1.7.0 - Jan 3, 2023
14-
-------------------
31+
1.7.0 - January 3, 2023
32+
-----------------------
1533

16-
* Add Python 3.11 support.
17-
* Add Python 3.10 support.
18-
* Drop Python 3.6 support (end-of-life was December 23, 2021).
19-
* Drop Python 2.7 support (end-of-life was January 1, 2020).
34+
* Add Python 3.10 and 3.11 support.
35+
* Drop support for Python 2.7 (EOL 2020-01-01), 3.6 (2021-12-23).
2036

2137
1.6.3 - July 15, 2021
2238
---------------------
@@ -37,8 +53,7 @@ Unreleased
3753
* fix: Aggregations return ``None`` if all values are ``None``, instead of raising an error. Note that ``Sum``, ``MaxLength`` and ``MaxPrecision`` continue to return ``0`` if all values are ``None``. (#706)
3854
* fix: Ensure files are closed when errors occur. (#734)
3955
* build: Make PyICU an optional dependency.
40-
* Drop Python 3.5 support (end-of-life was September 13, 2020).
41-
* Drop Python 3.4 support (end-of-life was March 18, 2019).
56+
* Drop support for Python 3.4 (2019-03-18), 3.5 (2020-09-13).
4257

4358
1.6.2 - March 10, 2021
4459
----------------------

agate/__init__.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
import agate.csv_py3 as csv
32
from agate.aggregations import *
43
from agate.columns import Column

agate/aggregations/base.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
from agate.exceptions import UnsupportedAggregationError
32

43

agate/computations/base.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
class Computation: # pragma: no cover
32
"""
43
Computations produce a new column by performing a calculation on each row.

agate/computations/percent.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
from agate.aggregations.has_nulls import HasNulls
32
from agate.aggregations.sum import Sum
43
from agate.computations.base import Computation

agate/config.py

+8
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626
+-------------------------+------------------------------------------+-----------------------------------------+
2727
| ellipsis_chars | Characters to render for ellipsis | '...' |
2828
+-------------------------+------------------------------------------+-----------------------------------------+
29+
| text_truncation_chars | Characters for truncated text values | '...' |
30+
+-------------------------+------------------------------------------+-----------------------------------------+
31+
| number_truncation_chars | Characters for truncated number values | '…' |
32+
+-------------------------+------------------------------------------+-----------------------------------------+
2933
3034
"""
3135

@@ -50,6 +54,10 @@
5054
'tick_char': '+',
5155
#: Characters to render for ellipsis
5256
'ellipsis_chars': '...',
57+
#: Characters for truncated text values
58+
'text_truncation_chars': '...',
59+
#: Characters for truncated number values
60+
'number_truncation_chars': '…',
5361
}
5462

5563

agate/data_types/base.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
from agate.exceptions import CastError
32

43
#: Default values which will be automatically cast to :code:`None`

agate/data_types/date_time.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ class DateTime(DataType):
1616
A formatting string for :meth:`datetime.datetime.strptime` to use
1717
instead of using regex-based parsing.
1818
:param timezone:
19-
A `pytz <https://pytz.sourceforge.net/>`_ timezone to apply to each
20-
parsed date.
19+
A ``ZoneInfo`` timezone to apply to each parsed date.
2120
:param locale:
2221
A locale specification such as :code:`en_US` or :code:`de_DE` to use
2322
for parsing formatted datetimes.

agate/data_types/number.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,11 @@ def __init__(self, locale='en_US', group_symbol=None, decimal_symbol=None,
4343
with warnings.catch_warnings():
4444
warnings.simplefilter("ignore")
4545

46-
self.group_symbol = group_symbol or self.locale.number_symbols.get('group', ',')
47-
self.decimal_symbol = decimal_symbol or self.locale.number_symbols.get('decimal', '.')
46+
# Babel 2.14 support.
47+
# https://babel.pocoo.org/en/latest/changelog.html#possibly-backwards-incompatible-changes
48+
number_symbols = self.locale.number_symbols.get('latn', self.locale.number_symbols)
49+
self.group_symbol = group_symbol or number_symbols.get('group', ',')
50+
self.decimal_symbol = decimal_symbol or number_symbols.get('decimal', '.')
4851

4952
def cast(self, d):
5053
"""

agate/data_types/text.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
from agate.data_types.base import DataType
32

43

agate/table/find.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
def find(self, test):
32
"""
43
Find the first row that passes a test.

agate/table/from_object.py

+19
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,25 @@ def from_object(cls, obj, row_names=None, column_types=None):
4040
Not all rows are required to have the same keys. Missing elements will
4141
be filled in with null values.
4242
43+
Keys containing a slash (``/``) can collide with other keys. For example:
44+
45+
.. code-block:: python
46+
47+
{
48+
'a/b': 2,
49+
'a': {
50+
'b': False
51+
}
52+
}
53+
54+
Would generate:
55+
56+
.. code-block:: python
57+
58+
{
59+
'a/b': false
60+
}
61+
4362
:param obj:
4463
Filepath or file-like object from which to read JSON data.
4564
:param row_names:

agate/table/limit.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
def limit(self, start_or_stop=None, stop=None, step=None):
32
"""
43
Create a new table with fewer rows.

agate/table/pivot.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
from agate import utils
32
from agate.aggregations import Count
43

agate/table/print_html.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ def print_html(self, max_rows=20, max_columns=6, output=sys.stdout, max_column_w
4343
max_precision = float('inf')
4444

4545
ellipsis = config.get_option('ellipsis_chars')
46+
truncation = config.get_option('text_truncation_chars')
47+
len_truncation = len(truncation)
4648
locale = locale or config.get_option('default_locale')
4749

4850
rows_truncated = max_rows < len(self._rows)
@@ -93,7 +95,7 @@ def print_html(self, max_rows=20, max_columns=6, output=sys.stdout, max_column_w
9395
v = str(v)
9496

9597
if max_column_width is not None and len(v) > max_column_width:
96-
v = '%s...' % v[:max_column_width - 3]
98+
v = '%s%s' % (v[:max_column_width - len_truncation], truncation)
9799

98100
formatted_row.append(v)
99101

agate/table/print_table.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ def print_table(self, max_rows=20, max_columns=6, output=sys.stdout, max_column_
4545
max_precision = float('inf')
4646

4747
ellipsis = config.get_option('ellipsis_chars')
48+
truncation = config.get_option('text_truncation_chars')
49+
len_truncation = len(truncation)
4850
h_line = config.get_option('horizontal_line_char')
4951
v_line = config.get_option('vertical_line_char')
5052
locale = locale or config.get_option('default_locale')
@@ -54,7 +56,7 @@ def print_table(self, max_rows=20, max_columns=6, output=sys.stdout, max_column_
5456
column_names = []
5557
for column_name in self.column_names[:max_columns]:
5658
if max_column_width is not None and len(column_name) > max_column_width:
57-
column_names.append('%s...' % column_name[:max_column_width - 3])
59+
column_names.append('%s%s' % (column_name[:max_column_width - len_truncation], truncation))
5860
else:
5961
column_names.append(column_name)
6062

@@ -102,7 +104,7 @@ def print_table(self, max_rows=20, max_columns=6, output=sys.stdout, max_column_
102104
v = str(v)
103105

104106
if max_column_width is not None and len(v) > max_column_width:
105-
v = '%s...' % v[:max_column_width - 3]
107+
v = '%s%s' % (v[:max_column_width - len_truncation], truncation)
106108

107109
if len(v) > widths[j]:
108110
widths[j] = len(v)

agate/table/to_csv.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ def to_csv(self, path, **kwargs):
66
Write this table to a CSV. This method uses agate's builtin CSV writer,
77
which supports unicode on both Python 2 and Python 3.
88
9-
`kwargs` will be passed through to the CSV writer.
9+
``kwargs`` will be passed through to the CSV writer.
10+
11+
The ``lineterminator`` defaults to the newline character (LF, ``\\n``).
1012
1113
:param path:
1214
Filepath or file-like object to write to.

agate/table/where.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
def where(self, test):
32
"""
43
Create a new :class:`.Table` with only those rows that pass a test.

agate/tableset/having.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
def having(self, aggregations, test):
32
"""
43
Create a new :class:`.TableSet` with only those tables that pass a test.

agate/tableset/proxy_methods.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
def bins(self, *args, **kwargs):
32
"""
43
Calls :meth:`.Table.bins` on each table in the TableSet.

agate/utils.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
from slugify import slugify as pslugify
1414

15+
from agate import config
1516
from agate.warns import warn_duplicate_column, warn_unnamed_column
1617

1718
#: Sentinal for use when `None` is an valid argument value
@@ -161,7 +162,7 @@ def make_number_formatter(decimal_places, add_ellipsis=False):
161162
Optionally add an ellipsis symbol at the end of a number
162163
"""
163164
fraction = '0' * decimal_places
164-
ellipsis = '…' if add_ellipsis else ''
165+
ellipsis = config.get_option('number_truncation_chars') if add_ellipsis else ''
165166
return ''.join(['#,##0.', fraction, ellipsis, ';-#,##0.', fraction, ellipsis])
166167

167168

docs/conf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
project = 'agate'
1414
copyright = '2017, Christopher Groskopf'
15-
version = '1.7.1'
15+
version = '1.9.1'
1616
release = version
1717

1818
# -- General configuration ---------------------------------------------------

docs/cookbook/datetime.rst

+13-5
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ The second way is to specify a timezone as an argument to the type constructor:
3434

3535
.. code-block:: python
3636
37-
import pytz
37+
try:
38+
from zoneinfo import ZoneInfo
39+
except ImportError:
40+
# Fallback for Python < 3.9
41+
from backports.zoneinfo import ZoneInfo
3842
39-
eastern = pytz.timezone('US/Eastern')
43+
eastern = ZoneInfo('US/Eastern')
4044
datetime_type = agate.DateTime(timezone=eastern)
4145
4246
In this case all timezones that are processed will be set to have the Eastern timezone. Note, the timezone will be **set**, not converted. You cannot use this method to convert your timezones from UTC to another timezone. To do that see :ref:`convert_timezones`.
@@ -60,17 +64,21 @@ If you load data from a spreadsheet in one timezone and you need to convert it t
6064

6165
.. code-block:: python
6266
63-
import pytz
67+
try:
68+
from zoneinfo import ZoneInfo
69+
except ImportError:
70+
# Fallback for Python < 3.9
71+
from backports.zoneinfo import ZoneInfo
6472
65-
us_eastern = pytz.timezone('US/Eastern')
73+
us_eastern = ZoneInfo('US/Eastern')
6674
datetime_type = agate.DateTime(timezone=us_eastern)
6775
6876
column_names = ['what', 'when']
6977
column_types = [text_type, datetime_type]
7078
7179
table = agate.Table.from_csv('events.csv', columns)
7280
73-
rome = timezone('Europe/Rome')
81+
rome = ZoneInfo('Europe/Rome')
7482
timezone_shifter = agate.Formula(lambda r: r['when'].astimezone(rome))
7583
7684
table = agate.Table.compute([

0 commit comments

Comments
 (0)