python-stdnum branch master updated. 1.18-11-g7e84c05
[
Date Prev][
Date Next]
[
Thread Prev][
Thread Next]
python-stdnum branch master updated. 1.18-11-g7e84c05
- From: Commits of the python-stdnum project <python-stdnum-commits [at] lists.arthurdejong.org>
- To: python-stdnum-commits [at] lists.arthurdejong.org
- Reply-to: python-stdnum-users [at] lists.arthurdejong.org, python-stdnum-commits [at] lists.arthurdejong.org
- Subject: python-stdnum branch master updated. 1.18-11-g7e84c05
- Date: Sat, 18 Mar 2023 16:31:10 +0100 (CET)
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "python-stdnum".
The branch, master has been updated
via 7e84c05bf1535ce3e645789cc7e2baf81278f7ae (commit)
from bf1bdfe7823ebc1206033d852412c966a3df611b (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
https://arthurdejong.org/git/python-stdnum/commit/?id=7e84c05bf1535ce3e645789cc7e2baf81278f7ae
commit 7e84c05bf1535ce3e645789cc7e2baf81278f7ae
Author: Arthur de Jong <arthur@arthurdejong.org>
Date: Sat Mar 18 16:08:52 2023 +0100
Extend date parsing in GS1-128
Some new AIs have new date formats or have changed the way optional
components of formats are defined.
diff --git a/stdnum/gs1_128.py b/stdnum/gs1_128.py
index 0bac88d..5ebf5ea 100644
--- a/stdnum/gs1_128.py
+++ b/stdnum/gs1_128.py
@@ -1,7 +1,7 @@
# gs1_128.py - functions for handling GS1-128 codes
#
# Copyright (C) 2019 Sergi Almacellas Abellana
-# Copyright (C) 2020-2021 Arthur de Jong
+# Copyright (C) 2020-2023 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -103,22 +103,32 @@ def _encode_value(fmt, _type, value):
_encode_value('N6', _type, value[0]),
_encode_value('N6', _type, value[1]))
elif isinstance(value, datetime.date):
- if fmt == 'N10':
+ if fmt in ('N6', 'N6..12'):
+ return value.strftime('%y%m%d')
+ elif fmt == 'N10':
return value.strftime('%y%m%d%H%M')
- elif fmt == 'N8+N..4':
+ elif fmt in ('N6+N..4', 'N6[+N..4]'):
+ value = datetime.datetime.strftime(value, '%y%m%d%H%M')
+ if value.endswith('00'):
+ value = value[:-2]
+ if value.endswith('00'):
+ value = value[:-2]
+ return value
+ elif fmt in ('N8+N..4', 'N8[+N..4]'):
value = datetime.datetime.strftime(value, '%y%m%d%H%M%S')
if value.endswith('00'):
value = value[:-2]
if value.endswith('00'):
value = value[:-2]
return value
- return value.strftime('%y%m%d')
+ else: # pragma: no cover (all formats should be covered)
+ raise ValueError('unsupported format: %s' % fmt)
return str(value)
def _max_length(fmt, _type):
"""Determine the maximum length based on the format ad type."""
- length = sum(int(re.match(r'^[NXY][0-9]*?[.]*([0-9]+)$', x).group(1)) for
x in fmt.split('+'))
+ length = sum(int(re.match(r'^[NXY][0-9]*?[.]*([0-9]+)[\[\]]?$',
x).group(1)) for x in fmt.split('+'))
if _type == 'decimal':
length += 1
return length
@@ -142,21 +152,22 @@ def _decode_value(fmt, _type, value):
value = value[:-digits] + '.' + value[-digits:]
return decimal.Decimal(value)
elif _type == 'date':
- if fmt == 'N8+N..4':
- return datetime.datetime.strptime(value,
'%y%m%d%H%M%S'[:len(value)])
- elif len(value) == 10:
- return datetime.datetime.strptime(value, '%y%m%d%H%M')
- elif len(value) == 12:
- return (_decode_value(fmt, _type, value[:6]), _decode_value(fmt,
_type, value[6:]))
- elif len(value) == 6 and value[4:] == '00':
- # When day == '00', it must be interpreted as last day of month
- date = datetime.datetime.strptime(value[:4], '%y%m')
- if date.month == 12:
- date = date.replace(day=31)
+ if len(value) == 6:
+ if value[4:] == '00':
+ # When day == '00', it must be interpreted as last day of month
+ date = datetime.datetime.strptime(value[:4], '%y%m')
+ if date.month == 12:
+ date = date.replace(day=31)
+ else:
+ date = date.replace(month=date.month + 1, day=1) -
datetime.timedelta(days=1)
+ return date.date()
else:
- date = date.replace(month=date.month + 1, day=1) -
datetime.timedelta(days=1)
- return date.date()
- return datetime.datetime.strptime(value, '%y%m%d').date()
+ return datetime.datetime.strptime(value, '%y%m%d').date()
+ elif len(value) == 12 and fmt in ('N12', 'N6..12'):
+ return (_decode_value('N6', _type, value[:6]), _decode_value('N6',
_type, value[6:]))
+ else:
+ # other lengths are interpreted as variable-length datetime values
+ return datetime.datetime.strptime(value,
'%y%m%d%H%M%S'[:len(value)])
elif _type == 'int':
return int(value)
return value.strip()
@@ -223,7 +234,7 @@ def encode(data, separator='', parentheses=False):
fixed_values = []
variable_values = []
for inputai, value in sorted(data.items()):
- ai, info = _gs1_aidb.info(inputai)[0]
+ ai, info = _gs1_aidb.info(str(inputai))[0]
if not info:
raise InvalidComponent()
# validate the value if we have a custom module for it
diff --git a/stdnum/gs1_ai.dat b/stdnum/gs1_ai.dat
index fcc5d16..cd6e33e 100644
--- a/stdnum/gs1_ai.dat
+++ b/stdnum/gs1_ai.dat
@@ -1,5 +1,5 @@
# generated from https://www.gs1.org/standards/barcodes/application-identifiers
-# on 2022-11-13 16:58:11.050076
+# on 2023-03-18 14:23:58.680562
00 format="N18" type="str" name="SSCC" description="Serial Shipping Container
Code (SSCC)"
01 format="N14" type="str" name="GTIN" description="Global Trade Item Number
(GTIN)"
02 format="N14" type="str" name="CONTENT" description="Global Trade Item
Number (GTIN) of contained trade items"
@@ -15,14 +15,14 @@
22 format="X..20" type="str" fnc1="1" name="CPV" description="Consumer product
variant"
235 format="X..28" type="str" fnc1="1" name="TPX" description="Third Party
Controlled, Serialised Extension of Global Trade Item Number (GTIN) (TPX)"
240 format="X..30" type="str" fnc1="1" name="ADDITIONAL ID"
description="Additional product identification assigned by the manufacturer"
-241 format="X..30" type="str" fnc1="1" name="CUST. PART NO."
description="Customer part number"
+241 format="X..30" type="str" fnc1="1" name="CUST. PART No."
description="Customer part number"
242 format="N..6" type="str" fnc1="1" name="MTO VARIANT"
description="Made-to-Order variation number"
243 format="X..20" type="str" fnc1="1" name="PCN" description="Packaging
component number"
250 format="X..30" type="str" fnc1="1" name="SECONDARY SERIAL"
description="Secondary serial number"
251 format="X..30" type="str" fnc1="1" name="REF. TO SOURCE"
description="Reference to source entity"
-253 format="N13+X..17" type="str" fnc1="1" name="GDTI" description="Global
Document Type Identifier (GDTI)"
+253 format="N13[+X..17]" type="str" fnc1="1" name="GDTI" description="Global
Document Type Identifier (GDTI)"
254 format="X..20" type="str" fnc1="1" name="GLN EXTENSION COMPONENT"
description="Global Location Number (GLN) extension component"
-255 format="N13+N..12" type="str" fnc1="1" name="GCN" description="Global
Coupon Number (GCN)"
+255 format="N13[+N..12]" type="str" fnc1="1" name="GCN" description="Global
Coupon Number (GCN)"
30 format="N..8" type="int" fnc1="1" name="VAR. COUNT" description="Variable
count of items (variable measure trade item)"
310 format="N6" type="decimal" name="NET WEIGHT (kg)" description="Net weight,
kilograms (variable measure trade item)"
311 format="N6" type="decimal" name="LENGTH (m)" description="Length or first
dimension, metres (variable measure trade item)"
@@ -92,15 +92,15 @@
411 format="N13" type="str" name="BILL TO" description="Bill to / Invoice to
Global Location Number (GLN)"
412 format="N13" type="str" name="PURCHASE FROM" description="Purchased from
Global Location Number (GLN)"
413 format="N13" type="str" name="SHIP FOR LOC" description="Ship for /
Deliver for - Forward to Global Location Number (GLN)"
-414 format="N13" type="str" name="LOC No" description="Identification of a
physical location - Global Location Number (GLN)"
+414 format="N13" type="str" name="LOC No." description="Identification of a
physical location - Global Location Number (GLN)"
415 format="N13" type="str" name="PAY TO" description="Global Location Number
(GLN) of the invoicing party"
416 format="N13" type="str" name="PROD/SERV LOC" description="Global Location
Number (GLN) of the production or service location"
417 format="N13" type="str" name="PARTY" description="Party Global Location
Number (GLN)"
420 format="X..20" type="str" fnc1="1" name="SHIP TO POST" description="Ship
to / Deliver to postal code within a single postal authority"
421 format="N3+X..9" type="str" fnc1="1" name="SHIP TO POST" description="Ship
to / Deliver to postal code with ISO country code"
422 format="N3" type="int" fnc1="1" name="ORIGIN" description="Country of
origin of a trade item"
-423 format="N3+N..12" type="str" fnc1="1" name="COUNTRY - INITIAL PROCESS."
description="Country of initial processing"
-424 format="N3" type="int" fnc1="1" name="COUNTRY - PROCESS."
description="Country of processing"
+423 format="N3+N..12" type="str" fnc1="1" name="COUNTRY - INITIAL PROCESS"
description="Country of initial processing"
+424 format="N3" type="int" fnc1="1" name="COUNTRY - PROCESS"
description="Country of processing"
425 format="N3+N..12" type="str" fnc1="1" name="COUNTRY - DISASSEMBLY"
description="Country of disassembly"
426 format="N3" type="int" fnc1="1" name="COUNTRY - FULL PROCESS"
description="Country covering full process chain"
427 format="X..3" type="str" fnc1="1" name="ORIGIN SUBDIVISION"
description="Country subdivision Of origin"
@@ -113,6 +113,7 @@
4306 format="X..70" type="str" fnc1="1" name="SHIP TO REG"
description="Ship-to / Deliver-to region"
4307 format="X2" type="str" fnc1="1" name="SHIP TO COUNTRY"
description="Ship-to / Deliver-to country code"
4308 format="X..30" type="str" fnc1="1" name="SHIP TO PHONE"
description="Ship-to / Deliver-to telephone number"
+4309 format="N20" type="str" fnc1="1" name="SHIP TO GEO" description="Ship-to
/ Deliver-to GEO location"
4310 format="X..35" type="str" fnc1="1" name="RTN TO COMP"
description="Return-to company name"
4311 format="X..35" type="str" fnc1="1" name="RTN TO NAME"
description="Return-to contact"
4312 format="X..70" type="str" fnc1="1" name="RTN TO ADD1"
description="Return-to address line 1"
@@ -127,8 +128,8 @@
4321 format="N1" type="str" fnc1="1" name="DANGEROUS GOODS"
description="Dangerous goods flag"
4322 format="N1" type="str" fnc1="1" name="AUTH TO LEAVE"
description="Authority to leave"
4323 format="N1" type="str" fnc1="1" name="SIG REQUIRED"
description="Signature required flag"
-4324 format="N10" type="date" fnc1="1" name="NOT BEF DEL DT" description="Not
before delivery date time"
-4325 format="N10" type="date" fnc1="1" name="NOT AFT DEL DT" description="Not
after delivery date time"
+4324 format="N10" type="date" fnc1="1" name="NBEF DEL DT" description="Not
before delivery date time"
+4325 format="N10" type="date" fnc1="1" name="NAFT DEL DT" description="Not
after delivery date time"
4326 format="N6" type="date" fnc1="1" name="REL DATE" description="Release
date"
7001 format="N13" type="str" fnc1="1" name="NSN" description="NATO Stock
Number (NSN)"
7002 format="X..30" type="str" fnc1="1" name="MEAT CUT" description="UN/ECE
meat carcasses and cuts classification"
@@ -140,6 +141,7 @@
7008 format="X..3" type="str" fnc1="1" name="AQUATIC SPECIES"
description="Species for fishery purposes"
7009 format="X..10" type="str" fnc1="1" name="FISHING GEAR TYPE"
description="Fishing gear type"
7010 format="X..2" type="str" fnc1="1" name="PROD METHOD"
description="Production method"
+7011 format="N6[+N..4]" type="date" fnc1="1" name="TEST BY DATE"
description="Test by date"
7020 format="X..20" type="str" fnc1="1" name="REFURB LOT"
description="Refurbishment lot ID"
7021 format="X..20" type="str" fnc1="1" name="FUNC STAT"
description="Functional status"
7022 format="X..20" type="str" fnc1="1" name="REV STAT" description="Revision
status"
@@ -173,13 +175,13 @@
7239 format="X2+X..28" type="str" fnc1="1" name="CERT #10"
description="Certification reference"
7240 format="X..20" type="str" fnc1="1" name="PROTOCOL" description="Protocol
ID"
8001 format="N14" type="str" fnc1="1" name="DIMENSIONS" description="Roll
products (width, length, core diameter, direction, splices)"
-8002 format="X..20" type="str" fnc1="1" name="CMT No" description="Cellular
mobile telephone identifier"
+8002 format="X..20" type="str" fnc1="1" name="CMT No." description="Cellular
mobile telephone identifier"
8003 format="N14+X..16" type="str" fnc1="1" name="GRAI" description="Global
Returnable Asset Identifier (GRAI)"
8004 format="X..30" type="str" fnc1="1" name="GIAI" description="Global
Individual Asset Identifier (GIAI)"
8005 format="N6" type="str" fnc1="1" name="PRICE PER UNIT" description="Price
per unit of measure"
8006 format="N14+N2+N2" type="str" fnc1="1" name="ITIP"
description="Identification of an individual trade item piece (ITIP)"
8007 format="X..34" type="str" fnc1="1" name="IBAN" description="International
Bank Account Number (IBAN)"
-8008 format="N8+N..4" type="date" fnc1="1" name="PROD TIME" description="Date
and time of production"
+8008 format="N8[+N..4]" type="date" fnc1="1" name="PROD TIME"
description="Date and time of production"
8009 format="X..50" type="str" fnc1="1" name="OPTSEN" description="Optically
Readable Sensor Indicator"
8010 format="Y..30" type="str" fnc1="1" name="CPID"
description="Component/Part Identifier (CPID)"
8011 format="N..12" type="str" fnc1="1" name="CPID SERIAL"
description="Component/Part Identifier serial number (CPID SERIAL)"
@@ -188,7 +190,7 @@
8017 format="N18" type="str" fnc1="1" name="GSRN - PROVIDER"
description="Global Service Relation Number (GSRN) to identify the relationship
between an organisation offering services and the provider of services"
8018 format="N18" type="str" fnc1="1" name="GSRN - RECIPIENT"
description="Global Service Relation Number (GSRN) to identify the relationship
between an organisation offering services and the recipient of services"
8019 format="N..10" type="str" fnc1="1" name="SRIN" description="Service
Relation Instance Number (SRIN)"
-8020 format="X..25" type="str" fnc1="1" name="REF No" description="Payment
slip reference number"
+8020 format="X..25" type="str" fnc1="1" name="REF No." description="Payment
slip reference number"
8026 format="N14+N2+N2" type="str" fnc1="1" name="ITIP CONTENT"
description="Identification of pieces of a trade item (ITIP) contained in a
logistic unit"
8110 format="X..70" type="str" fnc1="1" name="" description="Coupon code
identification for use in North America"
8111 format="N4" type="str" fnc1="1" name="POINTS" description="Loyalty points
of a coupon"
diff --git a/tests/test_gs1_128.doctest b/tests/test_gs1_128.doctest
index 035f17c..3e99d52 100644
--- a/tests/test_gs1_128.doctest
+++ b/tests/test_gs1_128.doctest
@@ -44,6 +44,8 @@ will be converted to the correct representation.
Traceback (most recent call last):
...
InvalidComponent: ...
+>>> gs1_128.encode({'253': '1234567890005000123'})
+'2531234567890005000123'
If we have a separator we use it to separate variable-length values, otherwise
we pad all variable-length values to the maximum length (except the last one).
@@ -82,6 +84,10 @@ We generate dates in various formats, depending on the AI.
'(8008)18111912'
>>> gs1_128.encode({'8008': datetime.datetime(2018, 11, 19, 0, 0)},
>>> parentheses=True)
'(8008)18111900'
+>>> gs1_128.encode({'7011': datetime.date(2018, 11, 19)}, parentheses=True)
+'(7011)181119'
+>>> gs1_128.encode({'7011': datetime.datetime(2018, 11, 19, 12, 45)},
parentheses=True)
+'(7011)1811191245'
If we try to encode an invalid EAN we will get an error.
@@ -112,6 +118,8 @@
pprint.pprint(gs1_128.info('(01)38425876095074(17)181119(37)1 '))
Traceback (most recent call last):
...
InvalidComponent: ...
+>>> pprint.pprint(gs1_128.info('(253)1234567890005000123'))
+{'253': '1234567890005000123'}
We can decode decimal values from various formats.
@@ -134,6 +142,10 @@ We an decode date files from various formats.
{'7007': (datetime.date(2018, 11, 19), datetime.date(2018, 11, 21))}
>>> pprint.pprint(gs1_128.info('(8008)18111912'))
{'8008': datetime.datetime(2018, 11, 19, 12, 0)}
+>>> pprint.pprint(gs1_128.info('(7011)181119'))
+{'7011': datetime.date(2018, 11, 19)}
+>>> pprint.pprint(gs1_128.info('(7011)1811191245'))
+{'7011': datetime.datetime(2018, 11, 19, 12, 45)}
While the compact() function can clean up the number somewhat the validate()
diff --git a/update/gs1_ai.py b/update/gs1_ai.py
index 8d339ed..b642469 100755
--- a/update/gs1_ai.py
+++ b/update/gs1_ai.py
@@ -2,7 +2,7 @@
# update/gs1_ai.py - script to get GS1 application identifiers
#
-# Copyright (C) 2019 Arthur de Jong
+# Copyright (C) 2019-2023 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -72,7 +72,7 @@ if __name__ == '__main__':
print('# on %s' % datetime.datetime.utcnow())
for ai1, ai2, format, require_fnc1, name, description in group_ai_ranges():
_type = 'str'
- if re.match(r'^(N8\+)?N[0-9]*[.]*[0-9]+$', format) and 'date' in
description.lower():
+ if re.match(r'^(N[68]\[?\+)?N[0-9]*[.]*[0-9]+\]?$', format) and 'date'
in description.lower():
_type = 'date'
elif re.match(r'^N[.]*[0-9]+$', format) and 'count' in
description.lower():
_type = 'int'
-----------------------------------------------------------------------
Summary of changes:
stdnum/gs1_128.py | 51 ++++++++++++++++++++++++++++------------------
stdnum/gs1_ai.dat | 26 ++++++++++++-----------
tests/test_gs1_128.doctest | 12 +++++++++++
update/gs1_ai.py | 4 ++--
4 files changed, 59 insertions(+), 34 deletions(-)
hooks/post-receive
--
python-stdnum
- python-stdnum branch master updated. 1.18-11-g7e84c05,
Commits of the python-stdnum project