Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select the most appropriate string representation based on heuristic #28

Merged
merged 2 commits into from
Feb 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ exclude =
full =
importlib-metadata; python_version<"3.8"
configupdater>=3.0.1,<4
tomlkit>=0.9.2,<2
tomlkit>=0.10.0,<2
# atoml @ git+https://github.com/abravalheri/atoml@table-common-ancestor#egg=atoml
lite =
importlib-metadata; python_version<"3.8"
tomli-w>=0.4.0,<2
all =
configupdater>=3.0.1,<4
tomlkit>=0.9.2,<2
tomlkit>=0.10.0,<2
# atoml @ git+https://github.com/abravalheri/atoml@table-common-ancestor#egg=atoml
tomli-w>=0.4.0,<2

Expand Down
35 changes: 33 additions & 2 deletions src/ini2toml/drivers/full_toml.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@
item,
loads,
nl,
string,
table,
)
from tomlkit.items import AoT, Array, InlineTable, Item, Table
from tomlkit.items import AoT, Array, InlineTable, Item, String, Table
from tomlkit.toml_document import TOMLDocument

from ..errors import InvalidTOMLKey
Expand Down Expand Up @@ -59,6 +60,11 @@ def collapse(obj, root=False):
return obj


@collapse.register(str)
def _collapse_string(obj: str) -> String:
return _string(obj)


@collapse.register(Commented)
def _collapse_commented(obj: Commented, root=False) -> Item:
return create_item(obj.value_or(None), obj.comment)
Expand Down Expand Up @@ -235,7 +241,7 @@ def _convert_irepr_to_toml(irepr: IntermediateRepr, out: T) -> T:


def create_item(value, comment):
obj = item(value)
obj = _item(value)
if comment is not None:
obj.comment(comment)
return obj
Expand Down Expand Up @@ -291,3 +297,28 @@ def classify_list(seq: Sequence) -> Tuple[bool, int, int, bool, bool, int]:
has_nl = has_nl or "\n" in elem_repr

return is_aot, max_len, total_len, has_nl, has_nested, len(seq)


def _item(obj) -> Item:
if isinstance(obj, str):
return _string(obj)

return item(obj)


def _string(obj: str) -> String:
"""Try to guess the best TOML representation for a string"""
multiline = "\n" in obj
single_line = "".join(x.strip().rstrip("\\") for x in obj.splitlines())
literal = '"' in obj or "\\" in single_line

if multiline and not obj.startswith("\n"):
# TOML will automatically strip an starting newline
# so let's add it, since it is better for reading
obj = "\n" + obj

try:
return string(obj, literal=literal, multiline=multiline)
except ValueError:
# Literal strings are not always possible
return string(obj, multiline=multiline)
2 changes: 1 addition & 1 deletion tests/examples/django/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ dynamic = ["license", "version"]
requires-python = ">=3.8"
dependencies = [
"asgiref >= 3.3.2",
"backports.zoneinfo; python_version<\"3.9\"",
'backports.zoneinfo; python_version<"3.9"',
"sqlparse >= 0.2.2",
"tzdata; sys_platform == 'win32'",
]
Expand Down
16 changes: 14 additions & 2 deletions tests/examples/flask/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,22 @@ source = [
# B9 = bugbear opinions
# ISC = implicit-str-concat
select = "B, E, F, W, B9, ISC"
ignore = "\n# slice notation whitespace, invalid\nE203\n# import at top, too many circular import fixes\nE402\n# line length, handled by bugbear B950\nE501\n# bare except, handled by bugbear B001\nE722\n# bin op line break, invalid\nW503"
ignore = """
# slice notation whitespace, invalid
E203
# import at top, too many circular import fixes
E402
# line length, handled by bugbear B950
E501
# bare except, handled by bugbear B001
E722
# bin op line break, invalid
W503"""
# up to 88 allowed by bugbear B950
max-line-length = "80"
per-file-ignores = "\n# __init__ module exports names\nsrc/flask/__init__.py: F401"
per-file-ignores = """
# __init__ module exports names
src/flask/__init__.py: F401"""

[tool.mypy]
files = ["src/flask"]
Expand Down
87 changes: 79 additions & 8 deletions tests/examples/pandas/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,90 @@ parentdir_prefix = "pandas-"

[tool.flake8]
max-line-length = "88"
ignore = "\n# space before : (needed for how black formats slicing)\nE203,\n# line break before binary operator\nW503,\n# line break after binary operator\nW504,\n# module level import not at top of file\nE402,\n# do not assign a lambda expression, use a def\nE731,\n# found modulo formatter (incorrect picks up mod operations)\nS001,\n# controversial\nB005,\n# controversial\nB006,\n# controversial\nB007,\n# controversial\nB008,\n# setattr is used to side-step mypy\nB009,\n# getattr is used to side-step mypy\nB010,\n# tests use assert False\nB011,\n# tests use comparisons but not their returned value\nB015,\n# false positives\nB301"
exclude = "\ndoc/sphinxext/*.py,\ndoc/build/*.py,\ndoc/temp/*.py,\n.eggs/*.py,\nversioneer.py,\n# exclude asv benchmark environments from linting\nenv"
per-file-ignores = "\n# private import across modules\npandas/tests/*:PDF020\n# pytest.raises without match=\npandas/tests/extension/*:PDF009\n# os.remove\ndoc/make.py:PDF008\n# import from pandas._testing\npandas/testing.py:PDF014"
ignore = """
# space before : (needed for how black formats slicing)
E203,
# line break before binary operator
W503,
# line break after binary operator
W504,
# module level import not at top of file
E402,
# do not assign a lambda expression, use a def
E731,
# found modulo formatter (incorrect picks up mod operations)
S001,
# controversial
B005,
# controversial
B006,
# controversial
B007,
# controversial
B008,
# setattr is used to side-step mypy
B009,
# getattr is used to side-step mypy
B010,
# tests use assert False
B011,
# tests use comparisons but not their returned value
B015,
# false positives
B301"""
exclude = """
doc/sphinxext/*.py,
doc/build/*.py,
doc/temp/*.py,
.eggs/*.py,
versioneer.py,
# exclude asv benchmark environments from linting
env"""
per-file-ignores = """
# private import across modules
pandas/tests/*:PDF020
# pytest.raises without match=
pandas/tests/extension/*:PDF009
# os.remove
doc/make.py:PDF008
# import from pandas._testing
pandas/testing.py:PDF014"""

[tool.flake8-rst]
max-line-length = "84"
bootstrap = "\nimport numpy as np\nimport pandas as pd\n# avoiding error when importing again numpy or pandas\nnp\n# (in some cases we want to do it to show users)\npd"
ignore = "\n# space before : (needed for how black formats slicing)\nE203,\n# module level import not at top of file\nE402,\n# line break before binary operator\nW503,\n# Classes/functions in different blocks can generate those errors\n# expected 2 blank lines, found 0\nE302,\n# expected 2 blank lines after class or function definition, found 0\nE305,\n# We use semicolon at the end to avoid displaying plot objects\n# statement ends with a semicolon\nE703,\n# comparison to none should be 'if cond is none:'\nE711,"
exclude = "\ndoc/source/development/contributing_docstring.rst,\n# work around issue of undefined variable warnings\n# https://github.com/pandas-dev/pandas/pull/38837#issuecomment-752884156\ndoc/source/getting_started/comparison/includes/*.rst"
bootstrap = """
import numpy as np
import pandas as pd
# avoiding error when importing again numpy or pandas
np
# (in some cases we want to do it to show users)
pd"""
ignore = """
# space before : (needed for how black formats slicing)
E203,
# module level import not at top of file
E402,
# line break before binary operator
W503,
# Classes/functions in different blocks can generate those errors
# expected 2 blank lines, found 0
E302,
# expected 2 blank lines after class or function definition, found 0
E305,
# We use semicolon at the end to avoid displaying plot objects
# statement ends with a semicolon
E703,
# comparison to none should be 'if cond is none:'
E711,"""
exclude = """
doc/source/development/contributing_docstring.rst,
# work around issue of undefined variable warnings
# https://github.com/pandas-dev/pandas/pull/38837#issuecomment-752884156
doc/source/getting_started/comparison/includes/*.rst"""

[tool.codespell]
ignore-words-list = "ba,blocs,coo,hist,nd,sav,ser"
ignore-regex = "https://(\\w+\\.)+"
ignore-regex = 'https://(\w+\.)+'

[tool.coverage.run]
branch = true
Expand All @@ -114,7 +185,7 @@ exclude_lines = [
"pragma: no cover",
# Don't complain about missing debug-only code:
"def __repr__",
"if self\\.debug",
'if self\.debug',
# Don't complain if tests don't hit defensive assertion code:
"raise AssertionError",
"raise NotImplementedError",
Expand Down
2 changes: 1 addition & 1 deletion tests/examples/pluggy/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ classifiers = [
urls = {Homepage = "https://github.com/pytest-dev/pluggy"}
dynamic = ["license", "version"]
requires-python = ">=3.6"
dependencies = ["importlib-metadata>=0.12;python_version<\"3.8\""]
dependencies = ['importlib-metadata>=0.12;python_version<"3.8"']

[project.readme]
file = "README.rst"
Expand Down
14 changes: 11 additions & 3 deletions tests/examples/pyscaffold/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ classifiers = [
dynamic = ["license", "version"]
requires-python = ">=3.6"
dependencies = [
"importlib-metadata; python_version<\"3.8\"",
'importlib-metadata; python_version<"3.8"',
"appdirs>=1.4.4,<2",
"configupdater>=3.0,<4",
"setuptools>=46.1.0",
Expand Down Expand Up @@ -125,7 +125,9 @@ license-files = ["LICEN[CS]E*", "COPYING*", "NOTICE*", "AUTHORS*"]
# in order to write a coverage file that can be read by Jenkins.
# CAUTION: --cov flags may prohibit setting breakpoints while debugging.
# Comment those flags to avoid this pytest issue.
addopts = "--cov pyscaffold --cov-config .coveragerc --cov-report term-missing\n--verbose"
addopts = """
--cov pyscaffold --cov-config .coveragerc --cov-report term-missing
--verbose"""
# In order to use xdist, the developer can add, for example, the following
# arguments:
# --dist=load --numprocesses=auto
Expand Down Expand Up @@ -160,7 +162,13 @@ formats = "bdist_wheel"
max_line_length = "88"
# E203 and W503 have edge cases handled by black
extend_ignore = "E203, W503"
exclude = "\nsrc/pyscaffold/contrib\n.tox\nbuild\ndist\n.eggs\ndocs/conf.py"
exclude = """
src/pyscaffold/contrib
.tox
build
dist
.eggs
docs/conf.py"""

[tool.mypy]
ignore_missing_imports = true
Expand Down
2 changes: 1 addition & 1 deletion tests/examples/setuptools_docs/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ classifiers = [
dynamic = ["readme", "license", "version"]
dependencies = [
"requests",
"importlib; python_version == \"2.6\"",
'importlib; python_version == "2.6"',
]

[project.optional-dependencies]
Expand Down
10 changes: 6 additions & 4 deletions tests/examples/virtualenv/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ dependencies = [
"filelock>=3.0.0,<4",
"platformdirs>=2,<3",
"six>=1.9.0,<2", # keep it >=1.9.0 as it may cause problems on LTS platforms
"importlib-metadata>=0.12;python_version<\"3.8\"",
"importlib-resources>=1.0;python_version<\"3.7\"",
'importlib-metadata>=0.12;python_version<"3.8"',
'importlib-resources>=1.0;python_version<"3.7"',
"pathlib2>=2.3.3,<3;python_version < '3.4' and sys.platform != 'win32'",
]

Expand Down Expand Up @@ -99,7 +99,7 @@ testing = [
"pytest-mock>=2",
"pytest-randomly>=1",
"pytest-timeout>=1",
"packaging>=20.0;python_version>\"3.4\"",
'packaging>=20.0;python_version>"3.4"',
]

[project.scripts]
Expand Down Expand Up @@ -138,4 +138,6 @@ universal = true
markers = ["slow"]
junit_family = "xunit2"
addopts = "--tb=auto -ra --showlocals --no-success-flaky-report"
env = "PYTHONWARNINGS=ignore:DEPRECATION::pip._internal.cli.base_command\nPYTHONIOENCODING=utf-8"
env = """
PYTHONWARNINGS=ignore:DEPRECATION::pip._internal.cli.base_command
PYTHONIOENCODING=utf-8"""
4 changes: 2 additions & 2 deletions tests/examples/zipp/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ testing = [
"pytest >= 6",
"pytest-checkdocs >= 2.4",
"pytest-flake8",
"pytest-black >= 0.3.7; python_implementation != \"PyPy\"", # workaround for jaraco/skeleton#22
'pytest-black >= 0.3.7; python_implementation != "PyPy"', # workaround for jaraco/skeleton#22
"pytest-cov",
"pytest-mypy; python_implementation != \"PyPy\"", # workaround for jaraco/skeleton#22
'pytest-mypy; python_implementation != "PyPy"', # workaround for jaraco/skeleton#22
"pytest-enabler >= 1.0.1",
# local
"jaraco.itertools",
Expand Down
2 changes: 1 addition & 1 deletion tests/plugins/test_setuptools_pep621.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def test_convert_directives(plugin, parse, convert):
zip-safe = false # comment
package-dir = {"" = "src"}
install-requires = [
"importlib-metadata; python_version<\\"3.8\\"",
'importlib-metadata; python_version<"3.8"',
"configupdater>=3,<=4",
]

Expand Down