Skip to content

Commit e1d99d4

Browse files
authored
Merge branch 'main' into chore/release-3.17.0
2 parents f37b5db + 917601f commit e1d99d4

18 files changed

Lines changed: 477 additions & 369 deletions

.github/workflows/bandit.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
build:
1717
runs-on: ubuntu-latest
1818
steps:
19-
- uses: actions/checkout@v6
19+
- uses: actions/checkout@v7
2020
- name: Set up Python
2121
uses: actions/setup-python@v6
2222
with:

.github/workflows/cfn-nag.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
build:
2525
runs-on: ubuntu-latest
2626
steps:
27-
- uses: actions/checkout@v6
27+
- uses: actions/checkout@v7
2828
- name: Use Node.js
2929
uses: actions/setup-node@v6
3030
with:
@@ -41,7 +41,7 @@ jobs:
4141
run: |
4242
npm install -g aws-cdk
4343
cdk --version
44-
- uses: actions/checkout@v6
44+
- uses: actions/checkout@v7
4545
- name: Set up Python
4646
uses: actions/setup-python@v6
4747
with:

.github/workflows/check-pytest-xfails.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ jobs:
1515
Check:
1616
runs-on: ubuntu-latest
1717
steps:
18-
- uses: actions/checkout@v6
18+
- uses: actions/checkout@v7
1919
- name: check xfails
2020
run: if grep -ro "@pytest.mark.xfail()" tests/; then echo "xfails must catch a specific error, e.g. '@pytest.mark.xfail(raises=NotImplementedError)'" && exit 1; else echo "success" && exit 0; fi

.github/workflows/minimal-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
runs-on: ${{ matrix.platform }}
3434

3535
steps:
36-
- uses: actions/checkout@v6
36+
- uses: actions/checkout@v7
3737
- name: Set up Python ${{ matrix.python-version }}
3838
uses: actions/setup-python@v6
3939
with:

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
runs-on: ubuntu-latest
2323

2424
steps:
25-
- uses: actions/checkout@v6
25+
- uses: actions/checkout@v7
2626
- uses: hynek/build-and-inspect-python-package@v2
2727

2828

.github/workflows/snyk.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
security:
1515
runs-on: ubuntu-latest
1616
steps:
17-
- uses: actions/checkout@v6
17+
- uses: actions/checkout@v7
1818
- name: Run Snyk to check for vulnerabilities
1919
uses: snyk/actions/python-3.12@master
2020
continue-on-error: true # To make sure that SARIF upload gets called

.github/workflows/static-checking.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
python-version: ["3.10"]
2222

2323
steps:
24-
- uses: actions/checkout@v6
24+
- uses: actions/checkout@v7
2525
- name: Set up Python ${{ matrix.python-version }}
2626
uses: actions/setup-python@v6
2727
with:

awswrangler/athena/_write_iceberg.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,21 @@
2424
_logger: logging.Logger = logging.getLogger(__name__)
2525

2626

27+
def _escape_athena_string_literal(value: Any) -> str:
28+
# Used for caller-supplied values spliced inside SQL string literals, e.g.
29+
# COMMENT '<value>' or TBLPROPERTIES ('<key>'='<value>').
30+
#
31+
# The wrapping single quotes around the splice site are *delimiters* — they tell
32+
# Athena "this is a string literal" and are part of the DDL grammar, not escaping.
33+
# A naive splice f"'{value}'" lets a value containing ' close the literal and
34+
# append arbitrary DDL (e.g. LOCATION '...').
35+
#
36+
# Athena/Trino string literals have exactly one escape mechanism: a single quote
37+
# inside the literal must be doubled. Pre-doubling caller quotes here means the
38+
# whole value parses as one literal regardless of what it contains.
39+
return str(value).replace("'", "''")
40+
41+
2742
def _create_iceberg_table(
2843
df: pd.DataFrame,
2944
database: str,
@@ -50,13 +65,19 @@ def _create_iceberg_table(
5065
[
5166
f"{k} {v}"
5267
if (columns_comments is None or columns_comments.get(k) is None)
53-
else f"{k} {v} COMMENT '{columns_comments[k]}'"
68+
else f"{k} {v} COMMENT '{_escape_athena_string_literal(columns_comments[k])}'"
5469
for k, v in columns_types.items()
5570
]
5671
)
5772
partition_cols_str: str = f"PARTITIONED BY ({', '.join([col for col in partition_cols])})" if partition_cols else ""
5873
table_properties_str: str = (
59-
", " + ", ".join([f"'{key}'='{value}'" for key, value in additional_table_properties.items()])
74+
", "
75+
+ ", ".join(
76+
[
77+
f"'{_escape_athena_string_literal(key)}'='{_escape_athena_string_literal(value)}'"
78+
for key, value in additional_table_properties.items()
79+
]
80+
)
6081
if additional_table_properties
6182
else ""
6283
)

awswrangler/neptune/_gremlin_init.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@
88
from gremlin_python.process.anonymous_traversal import traversal
99
from gremlin_python.process.graph_traversal import GraphTraversalSource, __
1010
from gremlin_python.process.translator import Translator
11-
from gremlin_python.process.traversal import Cardinality, T
11+
from gremlin_python.process.traversal import Cardinality, T, TraversalStrategies
1212
from gremlin_python.structure.graph import Edge, Graph, Path, Property, Vertex, VertexProperty
1313

14+
def local_traversal_source() -> "GraphTraversalSource":
15+
# gremlinpython 3.8 removed Graph().traversal() and traversal().withGraph(Graph()).
16+
# We only need a traversal source to build bytecode that the Translator turns into
17+
# a query string — no remote connection or strategies are needed.
18+
return GraphTraversalSource(Graph(), TraversalStrategies())
19+
1420
__all__ = [
1521
"__",
1622
"Cardinality",
@@ -22,6 +28,8 @@
2228
"Property",
2329
"T",
2430
"Translator",
31+
"TraversalStrategies",
32+
"local_traversal_source",
2533
"traversal",
2634
"Vertex",
2735
"VertexProperty",

awswrangler/neptune/_neptune.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def to_property_graph(
170170
... )
171171
"""
172172
# check if ~id and ~label column exist and if not throw error
173-
g = gremlin.Graph().traversal()
173+
g = gremlin.local_traversal_source()
174174
is_edge_df = False
175175
is_update_df = True
176176
if "~id" in df.columns:
@@ -198,7 +198,7 @@ def to_property_graph(
198198
if index > 0 and index + 1 % batch_size == 0:
199199
res = _run_gremlin_insert(client, g)
200200
if res:
201-
g = gremlin.Graph().traversal()
201+
g = gremlin.local_traversal_source()
202202

203203
return _run_gremlin_insert(client, g)
204204

0 commit comments

Comments
 (0)