Commit 0ee426b2 by Sébastien Eustace

Merge branch 'master' into develop

parents 96ae5e5f 9e15fdf2
...@@ -225,7 +225,7 @@ Here is a breakdown of what exactly happens here: ...@@ -225,7 +225,7 @@ Here is a breakdown of what exactly happens here:
What interests us is `pbr (>=0.6,!=0.7,<1.0)`. What interests us is `pbr (>=0.6,!=0.7,<1.0)`.
At his point, poetry will choose `pbr==0.11.1` which is the latest version that matches the constraint. At this point, poetry will choose `pbr==0.11.1` which is the latest version that matches the constraint.
Next it will try to select `oslo.i18n==3.20.0` which is the latest version that matches `oslo.i18n (>=1.3.0)`. Next it will try to select `oslo.i18n==3.20.0` which is the latest version that matches `oslo.i18n (>=1.3.0)`.
...@@ -242,7 +242,7 @@ dependency. This means that **any** version of this package can be installed whi ...@@ -242,7 +242,7 @@ dependency. This means that **any** version of this package can be installed whi
can lead to compatibility issues. can lead to compatibility issues.
Also, you have to explicitly tell it to not update the locked packages when you Also, you have to explicitly tell it to not update the locked packages when you
installed new ones. This should be the default. install new ones. This should be the default.
#### Remove command #### Remove command
...@@ -740,7 +740,7 @@ This section describe the scripts or executable that will be installed when inst ...@@ -740,7 +740,7 @@ This section describe the scripts or executable that will be installed when inst
```toml ```toml
[tool.poetry.scripts] [tool.poetry.scripts]
poetry = 'poetry:console.run' poetry = 'poetry.console:run'
``` ```
After installing a package with the above toml, `poetry` will be a global command available from the command line that will execute `console.run` in the `poetry` package. After installing a package with the above toml, `poetry` will be a global command available from the command line that will execute `console.run` in the `poetry` package.
......
...@@ -31,9 +31,11 @@ your project and its dependencies. For now, it looks like this: ...@@ -31,9 +31,11 @@ your project and its dependencies. For now, it looks like this:
[tool.poetry] [tool.poetry]
name = "poetry-demo" name = "poetry-demo"
version = "0.1.0" version = "0.1.0"
authors = [ "Sébastien Eustace <sebastien@eustace.io>",] description = ""
authors = ["Sébastien Eustace <sebastien@eustace.io>"]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "*"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
pytest = "^3.4" pytest = "^3.4"
......
...@@ -54,6 +54,26 @@ the `--name` option: ...@@ -54,6 +54,26 @@ the `--name` option:
poetry new my-folder --name my-package poetry new my-folder --name my-package
``` ```
If you want to use a src folder, you can use the `--src` option:
```bash
poetry new --src my-package
```
That will create a folder structure as follows:
```text
my-package
├── pyproject.toml
├── README.rst
├── src
│ └── my_package
│ └── __init__.py
└── tests
├── __init__.py
└── test_my_package
```
## init ## init
This command will help you create a `pyproject.toml` file interactively This command will help you create a `pyproject.toml` file interactively
......
...@@ -32,3 +32,22 @@ with the new major version of your dependency. ...@@ -32,3 +32,22 @@ with the new major version of your dependency.
For example instead of using `>=3.4` you should use `~3.4` which allows all versions `<4.0`. For example instead of using `>=3.4` you should use `~3.4` which allows all versions `<4.0`.
The `^` operator works very well with libraries following [semantic versioning](https://semver.org). The `^` operator works very well with libraries following [semantic versioning](https://semver.org).
## Is tox supported?
For now, you can use Poetry with [tox](https://tox.readthedocs.io/en/latest/) by using something similar to what is done in the [Pendulum](https://github.com/sdispater/pendulum/blob/master/tox.ini) package.
Minimal viable `tox.ini` configuration file looks like this:
```INI
[tox]
skipsdist = True
envlist = py27, py36
[testenv]
whitelist_externals = poetry
skip_install = true
commands =
poetry install -v
poetry run pytest tests/
```
...@@ -63,7 +63,7 @@ and you have [configured your credentials](/repositories/#adding-credentials) pr ...@@ -63,7 +63,7 @@ and you have [configured your credentials](/repositories/#adding-credentials) pr
If you want to build your packages separately and later publish them, If you want to build your packages separately and later publish them,
just pass the `--no-build` option. just pass the `--no-build` option.
Once this is done, your library will be availbale to anyone. Once this is done, your library will be available to anyone.
## Publishing to a private repository ## Publishing to a private repository
......
...@@ -7,7 +7,7 @@ class NewCommand(Command): ...@@ -7,7 +7,7 @@ class NewCommand(Command):
new new
{ path : The path to create the project at. } { path : The path to create the project at. }
{ --name : Set the resulting package name. } { --name= : Set the resulting package name. }
{ --src : Use the src layout for the project. } { --src : Use the src layout for the project. }
""" """
......
...@@ -34,61 +34,46 @@ Tag: {tag} ...@@ -34,61 +34,46 @@ Tag: {tag}
class WheelBuilder(Builder): class WheelBuilder(Builder):
def __init__(self, poetry, venv, io, target_fp, original=None): def __init__(self, poetry, venv, io, target_dir=None, original=None):
super(WheelBuilder, self).__init__(poetry, venv, io) super(WheelBuilder, self).__init__(poetry, venv, io)
self._records = [] self._records = []
self._original_path = self._path self._original_path = self._path
self._target_dir = target_dir or (self._poetry.file.parent / "dist")
if original: if original:
self._original_path = original.file.parent self._original_path = original.file.parent
# Open the zip file ready to write
self._wheel_zip = zipfile.ZipFile(
target_fp, "w", compression=zipfile.ZIP_DEFLATED
)
@classmethod @classmethod
def make_in(cls, poetry, venv, io, directory, original=None): def make_in(cls, poetry, venv, io, directory=None, original=None):
# We don't know the final filename until metadata is loaded, so write to wb = WheelBuilder(poetry, venv, io, target_dir=directory, original=original)
# a temporary_file, and rename it afterwards.
(fd, temp_path) = tempfile.mkstemp(suffix=".whl", dir=str(directory))
os.close(fd)
try:
with open(temp_path, "w+b") as fp:
wb = WheelBuilder(poetry, venv, io, fp, original=original)
wb.build() wb.build()
wheel_path = directory / wb.wheel_filename
if wheel_path.exists():
os.unlink(str(wheel_path))
os.rename(temp_path, str(wheel_path))
except:
os.unlink(temp_path)
raise
@classmethod @classmethod
def make(cls, poetry, venv, io): def make(cls, poetry, venv, io):
"""Build a wheel in the dist/ directory, and optionally upload it. """Build a wheel in the dist/ directory, and optionally upload it."""
""" cls.make_in(poetry, venv, io)
dist_dir = poetry.file.parent / "dist"
try:
dist_dir.mkdir()
except FileExistsError:
pass
cls.make_in(poetry, venv, io, dist_dir)
def build(self): def build(self):
self._io.writeln(" - Building <info>wheel</info>") self._io.writeln(" - Building <info>wheel</info>")
try:
dist_dir = self._target_dir
if not dist_dir.exists():
dist_dir.mkdir()
(fd, temp_path) = tempfile.mkstemp(suffix=".whl")
with zipfile.ZipFile(
os.fdopen(fd, "w+b"), mode="w", compression=zipfile.ZIP_DEFLATED
) as zip_file:
self._build() self._build()
self.copy_module() self._copy_module(zip_file)
self.write_metadata() self._write_metadata(zip_file)
self.write_record() self._write_record(zip_file)
finally:
self._wheel_zip.close() wheel_path = dist_dir / self.wheel_filename
if wheel_path.exists():
wheel_path.unlink()
shutil.move(temp_path, str(wheel_path))
self._io.writeln(" - Built <fg=cyan>{}</>".format(self.wheel_filename)) self._io.writeln(" - Built <fg=cyan>{}</>".format(self.wheel_filename))
...@@ -120,7 +105,7 @@ class WheelBuilder(Builder): ...@@ -120,7 +105,7 @@ class WheelBuilder(Builder):
shutil.rmtree(str(self._path / pkg.name)) shutil.rmtree(str(self._path / pkg.name))
shutil.copytree(str(pkg), str(self._path / pkg.name)) shutil.copytree(str(pkg), str(self._path / pkg.name))
def copy_module(self): def _copy_module(self, wheel):
excluded = self.find_excluded_files() excluded = self.find_excluded_files()
src = self._module.path src = self._module.path
to_add = [] to_add = []
...@@ -155,29 +140,29 @@ class WheelBuilder(Builder): ...@@ -155,29 +140,29 @@ class WheelBuilder(Builder):
# Walk the files and compress them, # Walk the files and compress them,
# sorting everything so the order is stable. # sorting everything so the order is stable.
for full_path, rel_path in sorted(to_add, key=lambda x: x[1]): for full_path, rel_path in sorted(to_add, key=lambda x: x[1]):
self._add_file(full_path, rel_path) self._add_file(wheel, full_path, rel_path)
def write_metadata(self): def _write_metadata(self, wheel):
if ( if (
"scripts" in self._poetry.local_config "scripts" in self._poetry.local_config
or "plugins" in self._poetry.local_config or "plugins" in self._poetry.local_config
): ):
with self._write_to_zip(self.dist_info + "/entry_points.txt") as f: with self._write_to_zip(wheel, self.dist_info + "/entry_points.txt") as f:
self._write_entry_points(f) self._write_entry_points(f)
for base in ("COPYING", "LICENSE"): for base in ("COPYING", "LICENSE"):
for path in sorted(self._path.glob(base + "*")): for path in sorted(self._path.glob(base + "*")):
self._add_file(path, "%s/%s" % (self.dist_info, path.name)) self._add_file(wheel, path, "%s/%s" % (self.dist_info, path.name))
with self._write_to_zip(self.dist_info + "/WHEEL") as f: with self._write_to_zip(wheel, self.dist_info + "/WHEEL") as f:
self._write_wheel_file(f) self._write_wheel_file(f)
with self._write_to_zip(self.dist_info + "/METADATA") as f: with self._write_to_zip(wheel, self.dist_info + "/METADATA") as f:
self._write_metadata_file(f) self._write_metadata_file(f)
def write_record(self): def _write_record(self, wheel):
# Write a record of the files in the wheel # Write a record of the files in the wheel
with self._write_to_zip(self.dist_info + "/RECORD") as f: with self._write_to_zip(wheel, self.dist_info + "/RECORD") as f:
for path, hash, size in self._records: for path, hash, size in self._records:
f.write("{},sha256={},{}\n".format(path, hash, size)) f.write("{},sha256={},{}\n".format(path, hash, size))
# RECORD itself is recorded with no hash or size # RECORD itself is recorded with no hash or size
...@@ -230,7 +215,7 @@ class WheelBuilder(Builder): ...@@ -230,7 +215,7 @@ class WheelBuilder(Builder):
return "-".join(tag) return "-".join(tag)
def _add_file(self, full_path, rel_path): def _add_file(self, wheel, full_path, rel_path):
full_path, rel_path = str(full_path), str(rel_path) full_path, rel_path = str(full_path), str(rel_path)
if os.sep != "/": if os.sep != "/":
# We always want to have /-separated paths in the zip file and in # We always want to have /-separated paths in the zip file and in
...@@ -256,7 +241,7 @@ class WheelBuilder(Builder): ...@@ -256,7 +241,7 @@ class WheelBuilder(Builder):
hashsum.update(buf) hashsum.update(buf)
src.seek(0) src.seek(0)
self._wheel_zip.writestr(zinfo, src.read()) wheel.writestr(zinfo, src.read())
size = os.stat(full_path).st_size size = os.stat(full_path).st_size
hash_digest = urlsafe_b64encode(hashsum.digest()).decode("ascii").rstrip("=") hash_digest = urlsafe_b64encode(hashsum.digest()).decode("ascii").rstrip("=")
...@@ -264,7 +249,7 @@ class WheelBuilder(Builder): ...@@ -264,7 +249,7 @@ class WheelBuilder(Builder):
self._records.append((rel_path, hash_digest, size)) self._records.append((rel_path, hash_digest, size))
@contextlib.contextmanager @contextlib.contextmanager
def _write_to_zip(self, rel_path): def _write_to_zip(self, wheel, rel_path):
sio = StringIO() sio = StringIO()
yield sio yield sio
...@@ -277,7 +262,7 @@ class WheelBuilder(Builder): ...@@ -277,7 +262,7 @@ class WheelBuilder(Builder):
hashsum = hashlib.sha256(b) hashsum = hashlib.sha256(b)
hash_digest = urlsafe_b64encode(hashsum.digest()).decode("ascii").rstrip("=") hash_digest = urlsafe_b64encode(hashsum.digest()).decode("ascii").rstrip("=")
self._wheel_zip.writestr(zi, b, compress_type=zipfile.ZIP_DEFLATED) wheel.writestr(zi, b, compress_type=zipfile.ZIP_DEFLATED)
self._records.append((rel_path, hash_digest, len(b))) self._records.append((rel_path, hash_digest, len(b)))
def _write_entry_points(self, fp): def _write_entry_points(self, fp):
......
...@@ -195,7 +195,7 @@ class Provider: ...@@ -195,7 +195,7 @@ class Provider:
try: try:
venv.run("python", "setup.py", "egg_info") venv.run("python", "setup.py", "egg_info")
egg_info = list(tmp_dir.glob("*.egg-info"))[0] egg_info = next(tmp_dir.glob("**/*.egg-info"))
meta = pkginfo.UnpackedSDist(str(egg_info)) meta = pkginfo.UnpackedSDist(str(egg_info))
......
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