Commit 8e32aca5 by Sébastien Eustace

Change the poetry.toml file for the new, standardized pyproject.toml

parent 785361c8
...@@ -27,5 +27,5 @@ pip-log.txt ...@@ -27,5 +27,5 @@ pip-log.txt
setup.cfg setup.cfg
setup.py setup.py
MANIFEST.in MANIFEST.in
poetry.lock pyproject.lock
README.rst README.rst
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
### Changed ### Changed
- Changed the `poetry.toml` file for the new, standardized `pyproject.toml`.
- Dependencies of each package is now stored in `poetry.lock`. - Dependencies of each package is now stored in `poetry.lock`.
- Improved TOML file management. - Improved TOML file management.
- Dependency resolver now respects the root package python version requirements. - Dependency resolver now respects the root package python version requirements.
......
...@@ -28,13 +28,13 @@ See `poet help completions` for full details, but the gist is as simple as using ...@@ -28,13 +28,13 @@ See `poet help completions` for full details, but the gist is as simple as using
```bash ```bash
# Bash # Bash
poetry completions bash > /etc/bash_completion.d/poetry.bash-completion poetry completions bash > /etc/bash_completion.d/pyproject.bash-completion
# Bash (macOS/Homebrew) # Bash (macOS/Homebrew)
poetry completions bash > $(brew --prefix)/etc/bash_completion.d/poetry.bash-completion poetry completions bash > $(brew --prefix)/etc/bash_completion.d/pyproject.bash-completion
# Fish # Fish
poetry completions fish > ~/.config/fish/completions/poetry.fish poetry completions fish > ~/.config/fish/completions/pyproject.fish
# Zsh # Zsh
poetry completions zsh > ~/.zfunc/_poetry poetry completions zsh > ~/.zfunc/_poetry
...@@ -54,13 +54,13 @@ fpath+=~/.zfunc ...@@ -54,13 +54,13 @@ fpath+=~/.zfunc
## Introduction ## Introduction
`poetry` is a tool to handle dependencies installation, building and packaging of Python packages. `poetry` is a tool to handle dependencies installation, building and packaging of Python packages.
It only needs one file to do all of that: `poetry.toml`. It only needs one file to do all of that: the new, [standardized](https://www.python.org/dev/peps/pep-0518/) `pyproject.toml`.
```toml ```toml
[package] [tool.poetry]
name = "pypoet" name = "my-package"
version = "0.1.0" version = "0.1.0"
description = "Poet helps you declare, manage and install dependencies of Python projects, ensuring you have the right stack everywhere." description = "The description of the package"
license = "MIT" license = "MIT"
...@@ -70,17 +70,13 @@ authors = [ ...@@ -70,17 +70,13 @@ authors = [
readme = 'README.md' readme = 'README.md'
repository = "https://github.com/sdispater/poet" repository = "https://github.com/sdispater/poetry"
homepage = "https://github.com/sdispater/poet" homepage = "https://github.com/sdispater/poetry"
keywords = ['packaging', 'poet']
include = ['poet/**/*', 'LICENSE']
python-versions = "~2.7 || ^3.2"
keywords = ['packaging', 'poetry']
[dependencies] [tool.pyproject.dependencies]
python = "~2.7 || ^3.2" # Compatible python versions must be declared here
toml = "^0.9" toml = "^0.9"
requests = "^2.13" requests = "^2.13"
semantic_version = "^2.6" semantic_version = "^2.6"
...@@ -90,13 +86,13 @@ wheel = "^0.29" ...@@ -90,13 +86,13 @@ wheel = "^0.29"
pip-tools = "^1.8.2" pip-tools = "^1.8.2"
cleo = { git = "https://github.com/sdispater/cleo.git", branch = "master" } cleo = { git = "https://github.com/sdispater/cleo.git", branch = "master" }
[dev-dependencies] [tool.pyproject.dev-dependencies]
pytest = "^3.0" pytest = "^3.0"
pytest-cov = "^2.4" pytest-cov = "^2.4"
coverage = "<4.0" coverage = "<4.0"
httpretty = "^0.8.14" httpretty = "^0.8.14"
[scripts] [tool.pyproject.scripts]
poet = 'poet:app.run' poet = 'poet:app.run'
``` ```
...@@ -212,12 +208,12 @@ poetry new my-package ...@@ -212,12 +208,12 @@ poetry new my-package
will create a folder as follows: will create a folder as follows:
```text ```text
my-project my-package
├── poetry.toml ├── pyproject.toml
├── README.rst ├── README.rst
├── my_project ├── my_package
└── __init__.py └── __init__.py
── tests ── tests
├── __init__.py ├── __init__.py
└── test_my_package └── test_my_package
``` ```
...@@ -226,24 +222,24 @@ If you want to name your project differently than the folder, you can pass ...@@ -226,24 +222,24 @@ If you want to name your project differently than the folder, you can pass
the `--name` option: the `--name` option:
```bash ```bash
poetry new my-folder --my-package poetry new my-folder --name my-package
``` ```
### install ### install
The `install` command reads the `poetry.toml` file from the current directory, resolves the dependencies, The `install` command reads the `pyproject.toml` file from the current directory, resolves the dependencies,
and installs them. and installs them.
```bash ```bash
poetry install poetry install
``` ```
If there is a `poetry.lock` file in the current directory, If there is a `pyproject.lock` file in the current directory,
it will use the exact versions from there instead of resolving them. it will use the exact versions from there instead of resolving them.
This ensures that everyone using the library will get the same versions of the dependencies. This ensures that everyone using the library will get the same versions of the dependencies.
If there is no `poetry.lock` file, Poetry will create one after dependency resolution. If there is no `pyproject.lock` file, Poetry will create one after dependency resolution.
You can specify to the command that you do not want the development dependencies installed by passing You can specify to the command that you do not want the development dependencies installed by passing
the `--no-dev` option. the `--no-dev` option.
...@@ -267,14 +263,14 @@ poetry install -f mysql -f pgsql ...@@ -267,14 +263,14 @@ poetry install -f mysql -f pgsql
### update ### update
In order to get the latest versions of the dependencies and to update the `poetry.lock` file, In order to get the latest versions of the dependencies and to update the `pyproject.lock` file,
you should use the `update` command. you should use the `update` command.
```bash ```bash
poetry update poetry update
``` ```
This will resolve all dependencies of the project and write the exact versions into `poetry.lock`. This will resolve all dependencies of the project and write the exact versions into `pyproject.lock`.
If you just want to update a few packages and not all, you can list them as such: If you just want to update a few packages and not all, you can list them as such:
...@@ -284,12 +280,11 @@ poetry update requests toml ...@@ -284,12 +280,11 @@ poetry update requests toml
#### Options #### Options
* `--no-progress`: Removes the progress display that can mess with some terminals or scripts which don't handle backspace characters. * `--dry-run` : Outputs the operations but will not execute anything (implicitly enables --verbose).
### add ### add
The `add` command adds required packages to your `poetry.toml` and installs them. The `add` command adds required packages to your `pyproject.toml` and installs them.
If you do not specify a version constraint, If you do not specify a version constraint,
poetry will choose a suitable one based on the available package versions. poetry will choose a suitable one based on the available package versions.
...@@ -384,16 +379,16 @@ poetry search requests pendulum ...@@ -384,16 +379,16 @@ poetry search requests pendulum
### lock ### lock
This command locks (without installing) the dependencies specified in `poetry.toml`. This command locks (without installing) the dependencies specified in `pyproject.toml`.
```bash ```bash
poetry lock poetry lock
``` ```
## The `poetry.toml` file ## The `pyproject.toml` file
A `poetry.toml` file is composed of multiple sections. A `pyproject.toml` file is composed of multiple sections.
### package ### package
...@@ -519,7 +514,7 @@ Only the name and a version string are required in this case. ...@@ -519,7 +514,7 @@ Only the name and a version string are required in this case.
requests = "^2.13.0" requests = "^2.13.0"
``` ```
If you want to use a private repository, you can add it to your `poetry.toml` file, like so: If you want to use a private repository, you can add it to your `pyproject.toml` file, like so:
```toml ```toml
[[source]] [[source]]
...@@ -684,5 +679,5 @@ To match the example in the setuptools documentation, you would use the followin ...@@ -684,5 +679,5 @@ To match the example in the setuptools documentation, you would use the followin
## Resources ## Resources
* [Official Website](https://poetry.eustace.io) * [Official Website](https://pyproject.eustace.io)
* [Issue Tracker](https://github.com/sdispater/poetry/issues) * [Issue Tracker](https://github.com/sdispater/poetry/issues)
...@@ -35,11 +35,12 @@ If you do not specify a version constraint, poetry will choose a suitable one ba ...@@ -35,11 +35,12 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
if is_dev: if is_dev:
section = 'dev-dependencies' section = 'dev-dependencies'
original_content = self.poetry.locker.original.read() original_content = self.poetry.file.read()
content = self.poetry.locker.original.read() content = self.poetry.file.read()
poetry_content = content['tool']['poetry']
for name in packages: for name in packages:
for key in content[section]: for key in poetry_content[section]:
if key.lower() == name.lower(): if key.lower() == name.lower():
raise ValueError(f'Package {name} is already present') raise ValueError(f'Package {name} is already present')
...@@ -52,10 +53,10 @@ If you do not specify a version constraint, poetry will choose a suitable one ba ...@@ -52,10 +53,10 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
parser.parse_constraints(constraint) parser.parse_constraints(constraint)
for name, constraint in requirements.items(): for name, constraint in requirements.items():
content[section][name] = constraint poetry_content[section][name] = constraint
# Write new content # Write new content
self.poetry.locker.original.write(content) self.poetry.file.write(content)
# Cosmetic new line # Cosmetic new line
self.line('') self.line('')
...@@ -77,7 +78,7 @@ If you do not specify a version constraint, poetry will choose a suitable one ba ...@@ -77,7 +78,7 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
try: try:
status = installer.run() status = installer.run()
except Exception: except Exception:
self.poetry.locker.original.write(original_content) self.poetry.file.write(original_content)
raise raise
...@@ -90,7 +91,7 @@ If you do not specify a version constraint, poetry will choose a suitable one ba ...@@ -90,7 +91,7 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
'to its original content.' 'to its original content.'
) )
self.poetry.locker.original.write(original_content) self.poetry.file.write(original_content)
return status return status
......
...@@ -23,8 +23,9 @@ list of installed packages ...@@ -23,8 +23,9 @@ list of installed packages
packages = self.argument('packages') packages = self.argument('packages')
is_dev = self.option('dev') is_dev = self.option('dev')
original_content = self.poetry.locker.original.read() original_content = self.poetry.file.read()
content = self.poetry.locker.original.read() content = self.poetry.file.read()
poetry_content = content['tool']['poetry']
section = 'dependencies' section = 'dependencies'
if is_dev: if is_dev:
section = 'dev-dependencies' section = 'dev-dependencies'
...@@ -33,20 +34,20 @@ list of installed packages ...@@ -33,20 +34,20 @@ list of installed packages
requirements = {} requirements = {}
for name in packages: for name in packages:
found = False found = False
for key in content[section]: for key in poetry_content[section]:
if key.lower() == name.lower(): if key.lower() == name.lower():
found = True found = True
requirements[name] = content[section][name] requirements[name] = poetry_content[section][name]
break break
if not found: if not found:
raise ValueError(f'Package {name} not found') raise ValueError(f'Package {name} not found')
for key in requirements: for key in requirements:
del content[section][key] del poetry_content[section][key]
# Write the new content back # Write the new content back
self.poetry.locker.original.write(content) self.poetry.file.write(content)
# Update packages # Update packages
self.reset_poetry() self.reset_poetry()
...@@ -65,7 +66,7 @@ list of installed packages ...@@ -65,7 +66,7 @@ list of installed packages
try: try:
status = installer.run() status = installer.run()
except Exception: except Exception:
self.poetry.locker.original.write(original_content) self.poetry.file.write(original_content)
raise raise
...@@ -78,6 +79,6 @@ list of installed packages ...@@ -78,6 +79,6 @@ list of installed packages
'to its original content.' 'to its original content.'
) )
self.poetry.locker.original.write(original_content) self.poetry.file.write(original_content)
return status return status
...@@ -143,7 +143,7 @@ class Installer: ...@@ -143,7 +143,7 @@ class Installer:
self._io.writeln( self._io.writeln(
'<warning>' '<warning>'
'Warning: The lock file is not up to date with ' 'Warning: The lock file is not up to date with '
'the latest changes in composer.json. ' 'the latest changes in pyproject.toml. '
'You may be getting outdated dependencies. ' 'You may be getting outdated dependencies. '
'Run update to update them.' 'Run update to update them.'
'</warning>' '</warning>'
......
...@@ -90,25 +90,31 @@ class Layout(object): ...@@ -90,25 +90,31 @@ class Layout(object):
def _write_poetry(self, path): def _write_poetry(self, path):
output = { output = {
'package': { 'tool': {
'poetry': {
'name': self._project, 'name': self._project,
'version': self._version, 'version': self._version,
'authors': [self._author], 'authors': [self._author],
} }
} }
}
content = toml.dumps(output, preserve=True) content = toml.dumps(output, preserve=True)
output = { output = {
'tool': {
'poetry': {
'dependencies': {}, 'dependencies': {},
'dev-dependencies': { 'dev-dependencies': {
'pytest': '^3.4' 'pytest': '^3.4'
} }
} }
}
}
content += '\n' + toml.dumps(output, preserve=True) content += '\n' + toml.dumps(output, preserve=True)
poetry = path / 'poetry.toml' poetry = path / 'pyproject.toml'
with poetry.open('w') as f: with poetry.open('w') as f:
f.write(content) f.write(content)
......
...@@ -16,22 +16,19 @@ class Locker: ...@@ -16,22 +16,19 @@ class Locker:
'name', 'name',
'version', 'version',
'python-versions', 'python-versions',
'platform',
'dependencies', 'dependencies',
'dev-dependencies', 'dev-dependencies',
'source', 'source',
] ]
def __init__(self, lock: Path, original: Path): def __init__(self, lock: Path, local_config: dict):
self._lock = TomlFile(lock) self._lock = TomlFile(lock)
self._original = TomlFile(original) self._local_config = local_config
self._lock_data = None self._lock_data = None
self._content_hash = self._get_content_hash() self._content_hash = self._get_content_hash()
@property @property
def original(self) -> TomlFile:
return self._original
@property
def lock(self) -> TomlFile: def lock(self) -> TomlFile:
return self._lock return self._lock
...@@ -55,10 +52,11 @@ class Locker: ...@@ -55,10 +52,11 @@ class Locker:
""" """
Checks whether the lock file is still up to date with the current hash. Checks whether the lock file is still up to date with the current hash.
""" """
lock = self._lock.read() lock = self._lock.read(True)
metadata = lock.get('metadata', {})
if 'content-hash' in lock: if 'content-hash' in metadata:
return self._content_hash == lock['content-hash'] return self._content_hash == lock['metadata']['content-hash']
return False return False
...@@ -140,16 +138,11 @@ class Locker: ...@@ -140,16 +138,11 @@ class Locker:
""" """
Returns the sha256 hash of the sorted content of the composer file. Returns the sha256 hash of the sorted content of the composer file.
""" """
content = self._original.read() content = self._local_config
relevant_content = {} relevant_content = {}
for key in self._relevant_keys:
package = content['package'] relevant_content[key] = content.get(key)
for key in ['name', 'version', 'python-versions', 'platform']:
relevant_content[key] = package.get(key, '')
for key in ['dependencies', 'dev-dependencies']:
relevant_content[key] = content[key]
content_hash = sha256( content_hash = sha256(
json.dumps(relevant_content, sort_keys=True).encode() json.dumps(relevant_content, sort_keys=True).encode()
...@@ -163,7 +156,7 @@ class Locker: ...@@ -163,7 +156,7 @@ class Locker:
'No lockfile found. Unable to read locked packages' 'No lockfile found. Unable to read locked packages'
) )
return self._lock.read() return self._lock.read(True)
def _lock_packages(self, def _lock_packages(self,
packages: List['poetry.packages.Package']) -> list: packages: List['poetry.packages.Package']) -> list:
......
...@@ -13,9 +13,11 @@ class Poetry: ...@@ -13,9 +13,11 @@ class Poetry:
VERSION = '0.2.0' VERSION = '0.2.0'
def __init__(self, def __init__(self,
file: Path,
config: dict, config: dict,
package: Package, package: Package,
locker: Locker): locker: Locker):
self._file = TomlFile(file)
self._package = package self._package = package
self._config = config self._config = config
self._locker = locker self._locker = locker
...@@ -29,6 +31,10 @@ class Poetry: ...@@ -29,6 +31,10 @@ class Poetry:
self._pool.add_repository(PyPiRepository()) self._pool.add_repository(PyPiRepository())
@property @property
def file(self):
return self._file
@property
def package(self) -> Package: def package(self) -> Package:
return self._package return self._package
...@@ -46,37 +52,42 @@ class Poetry: ...@@ -46,37 +52,42 @@ class Poetry:
@classmethod @classmethod
def create(cls, cwd) -> 'Poetry': def create(cls, cwd) -> 'Poetry':
poetry_file = Path(cwd) / 'poetry.toml' poetry_file = Path(cwd) / 'pyproject.toml'
if not poetry_file.exists(): if not poetry_file.exists():
raise RuntimeError( raise RuntimeError(
f'Poetry could not find a poetry.json file in {cwd}' f'Poetry could not find a pyproject.toml file in {cwd}'
) )
# TODO: validate file content # TODO: validate file content
local_config = TomlFile(poetry_file.as_posix()).read() local_config = TomlFile(poetry_file.as_posix()).read(True)
if 'tool' not in local_config or 'poetry' not in local_config['tool']:
raise RuntimeError(
f'[tool.poetry] section not found in {poetry_file.name}'
)
local_config = local_config['tool']['poetry']
# Load package # Load package
package_config = local_config['package'] name = local_config['name']
name = package_config['name'] pretty_version = local_config['version']
pretty_version = package_config['version']
version = normalize_version(pretty_version) version = normalize_version(pretty_version)
package = Package(name, version, pretty_version) package = Package(name, version, pretty_version)
if 'python-versions' in package_config: if 'platform' in local_config:
package.python_versions = package_config['python-versions'] package.platform = local_config['platform']
if 'platform' in package_config:
package.platform = package_config['platform']
if 'dependencies' in local_config: if 'dependencies' in local_config:
for name, constraint in local_config['dependencies'].items(): for name, constraint in local_config['dependencies'].items():
if name.lower() == 'python':
package.python_versions = constraint
continue
package.add_dependency(name, constraint) package.add_dependency(name, constraint)
if 'dev-dependencies' in local_config: if 'dev-dependencies' in local_config:
for name, constraint in local_config['dev-dependencies'].items(): for name, constraint in local_config['dev-dependencies'].items():
package.add_dependency(name, constraint, category='dev') package.add_dependency(name, constraint, category='dev')
locker = Locker(poetry_file.with_suffix('.lock'), poetry_file) locker = Locker(poetry_file.with_suffix('.lock'), local_config)
return cls(local_config, package, locker) return cls(poetry_file, local_config, package, locker)
...@@ -5,8 +5,10 @@ from . import raw ...@@ -5,8 +5,10 @@ from . import raw
class CascadeDict: class CascadeDict:
""" """
A dict-like object made up of one or more other dict-like objects where querying for an item cascade-gets A dict-like object made up of one or more other dict-like objects
it from all the internal dicts in order of their listing, and setting an item sets it on the first dict listed. where querying for an item cascade-gets it from all the internal dicts
in order of their listing, and setting an item
sets it on the first dict listed.
""" """
def __init__(self, *internal_dicts): def __init__(self, *internal_dicts):
...@@ -17,7 +19,7 @@ class CascadeDict: ...@@ -17,7 +19,7 @@ class CascadeDict:
""" """
Returns another instance with one more dict cascaded at the end. Returns another instance with one more dict cascaded at the end.
""" """
return CascadeDict(self._internal_dicts, one_more_dict,) return CascadeDict(*self._internal_dicts, one_more_dict)
def __getitem__(self, item): def __getitem__(self, item):
for d in self._internal_dicts: for d in self._internal_dicts:
......
...@@ -109,9 +109,13 @@ class TableElement(abstracttable.AbstractTable): ...@@ -109,9 +109,13 @@ class TableElement(abstracttable.AbstractTable):
end = len(tuple(self._sub_elements)) end = len(tuple(self._sub_elements))
self._sub_elements = self.sub_elements[:begin] + self.sub_elements[end:] self._sub_elements = self.sub_elements[:begin] + self.sub_elements[end:]
@property
def value(self): def value(self):
return self return self
def __eq__(self, other):
return self.primitive_value == other
def __iter__(self): def __iter__(self):
return iter(self.keys()) return iter(self.keys())
......
...@@ -17,30 +17,29 @@ class NamedDict(dict): ...@@ -17,30 +17,29 @@ class NamedDict(dict):
""" """
key can be an Name instance. key can be an Name instance.
When key is a path in the form of an Name instance, all the parents and grandparents of the value are When key is a path in the form of an Name instance,
created along the way as instances of NamedDict. If the parent of the value exists, it is replaced with a all the parents and grandparents of the value are
CascadeDict() that cascades the old parent value with a new NamedDict that contains the given child name created along the way as instances of NamedDict.
and value.
If the parent of the value exists, it is replaced with a
CascadeDict() that cascades the old parent value
with a new NamedDict that contains the given child name and value.
""" """
if isinstance(key, toplevels.Name): if isinstance(key, toplevels.Name):
obj = self
if len(key.sub_names) == 1: for i, name in enumerate(key.sub_names):
name = key.sub_names[0] if name in obj:
if name in self: if i == len(key.sub_names) - 1:
self[name] = CascadeDict(self[name], value) obj[name] = CascadeDict(obj[name], value)
else: else:
self[name] = value obj[name] = CascadeDict(NamedDict(), obj[name])
elif len(key.sub_names) > 1:
name = key.sub_names[0]
rest_of_key = key.drop(1)
if name in self:
named_dict = NamedDict()
named_dict[rest_of_key] = value
self[name] = CascadeDict(self[name], named_dict)
else: else:
self[name] = NamedDict() if i == len(key.sub_names) - 1:
self[name][rest_of_key] = value obj[name] = value
else:
obj[name] = NamedDict()
obj = obj[name]
else: else:
return dict.__setitem__(self, key, value) return dict.__setitem__(self, key, value)
...@@ -62,7 +61,6 @@ class NamedDict(dict): ...@@ -62,7 +61,6 @@ class NamedDict(dict):
self[key] = [value] self[key] = [value]
def __getitem__(self, item): def __getitem__(self, item):
if isinstance(item, toplevels.Name): if isinstance(item, toplevels.Name):
d = self d = self
for name in item.sub_names: for name in item.sub_names:
...@@ -71,13 +69,15 @@ class NamedDict(dict): ...@@ -71,13 +69,15 @@ class NamedDict(dict):
else: else:
return dict.__getitem__(self, item) return dict.__getitem__(self, item)
def __eq__(self, other):
return dict.__eq__(self, other)
def structure(table_toplevels): def structure(table_toplevels):
""" """
Accepts an ordered sequence of TopLevel instances and returns a navigable object structure representation of the Accepts an ordered sequence of TopLevel instances and returns a navigable
TOML file. object structure representation of the TOML file.
""" """
table_toplevels = tuple(table_toplevels) table_toplevels = tuple(table_toplevels)
obj = NamedDict() obj = NamedDict()
......
...@@ -16,7 +16,10 @@ class TomlFile: ...@@ -16,7 +16,10 @@ class TomlFile:
def path(self): def path(self):
return self._path return self._path
def read(self) -> dict: def read(self, raw=False) -> dict:
if raw:
return toml.loads(self._path.read_text())
return loads(self._path.read_text()) return loads(self._path.read_text())
def write(self, data) -> None: def write(self, data) -> None:
......
[package] [tool.poetry]
name = "poetry" name = "poetry"
version = "0.2.0" version = "0.2.0"
description = "Python dependency management and packaging made easy." description = "Python dependency management and packaging made easy."
python-versions = "^3.6"
license = "MIT"
authors = [ authors = [
"Sébastien Eustace <sebastien@eustace.io>" "Sébastien Eustace <sebastien@eustace.io>"
] ]
license = "MIT"
readme = "README.md" readme = "README.md"
...@@ -19,19 +15,14 @@ documentation = "https://poetry.eustace.io/docs" ...@@ -19,19 +15,14 @@ documentation = "https://poetry.eustace.io/docs"
keywords = ["packaging", "dependency", "poetry"] keywords = ["packaging", "dependency", "poetry"]
include = ['poetry/**/*', 'LICENSE'] # Requirements
[tool.poetry.dependencies]
python = "^3.6"
[dependencies]
cleo = "^0.6" cleo = "^0.6"
requests = "^2.18" requests = "^2.18"
toml = "^0.9"
cachy = "^0.1.0" cachy = "^0.1.0"
pip-tools = "^1.11" pip-tools = "^1.11"
toml = "^0.9.4"
[dev-dependencies] [tool.poetry.dev-dependencies]
pytest = "~3.4" pytest = "~3.4"
[scripts]
poetry = 'poetry:console.run'
from poetry.toml.structurer import NamedDict
from poetry.toml.toplevels import Name
from poetry.toml.prettify.elements.table import TableElement
def test_named_dict():
d = NamedDict()
d[Name(('root', 'sub1', 'sub2'))] = 'foo'
assert d['root']['sub1']['sub2'] == 'foo'
assert d['root'] == {
'sub1': {
'sub2': 'foo'
}
}
d = NamedDict()
d[Name(('root', 'ns'))] = TableElement({})
d[Name(('root', 'ns', 'sub2'))] = TableElement({})
d[Name(('root', 'ns', 'sub3'))] = TableElement({})
assert d['root']['ns']['sub2'] == {}
assert d['root']['ns']['sub3'] == {}
from poetry.toml import dumps
from poetry.toml import loads from poetry.toml import loads
from poetry.toml.prettify.errors import TOMLError from poetry.toml.prettify.errors import TOMLError
from poetry.toml.prettify.errors import DuplicateKeysError
from poetry.toml.prettify.errors import DuplicateTablesError
from poetry.toml.prettify.errors import InvalidTOMLFileError
def test_loading_toml_without_trailing_newline(): def test_loading_toml_without_trailing_newline():
...@@ -91,7 +87,7 @@ cwd = "./handlers" ...@@ -91,7 +87,7 @@ cwd = "./handlers"
REDIS_PASSWORD = "MYPASSWORD" REDIS_PASSWORD = "MYPASSWORD"
#REDIS_PASSWORD = "" #REDIS_PASSWORD = ""
""" """
print(f.dumps())
assert expected == f.dumps() assert expected == f.dumps()
......
[tool.poetry]
name = "poetry"
version = "0.2.0"
description = "Python dependency management and packaging made easy."
authors = [
"Sébastien Eustace <sebastien@eustace.io>"
]
license = "MIT"
readme = "README.md"
homepage = "https://poetry.eustace.io/"
repository = "https://github.com/sdispater/poet"
documentation = "https://poetry.eustace.io/docs"
keywords = ["packaging", "dependency", "poetry"]
# Requirements
[tool.poetry.dependencies]
python = "^3.6"
cleo = "^0.6"
requests = "^2.18"
toml = "^0.9"
cachy = "^0.1.0"
pip-tools = "^1.11"
[tool.poetry.dev-dependencies]
pytest = "~3.4"
...@@ -48,3 +48,12 @@ def test_toml_file(fixture): ...@@ -48,3 +48,12 @@ def test_toml_file(fixture):
assert len(apple) == 3 assert len(apple) == 3
banana = fruits[1] banana = fruits[1]
assert len(banana['variety'][0]['points']) == 3 assert len(banana['variety'][0]['points']) == 3
def test_pyproject_parsing(fixture):
f = TomlFile(fixture.with_name('pyproject.toml'))
content = f.read()
assert 'dependencies' in content['tool']['poetry']
assert content['tool']['poetry']['dependencies']['python'] == '^3.6'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment