We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
1.0.0b5 removes my private source from the lockfile
<!--
  Hi there! Thank you for discovering and submitting an issue.

  Before you submit this; let's make sure of a few things.
  Please make sure the following boxes are ticked if they are correct.
  If not, please try and fulfill these first.
-->

<!-- Checked checkbox should look like this: [x] -->
- [x] I am on the [latest](https://github.com/sdispater/poetry/releases/latest) Poetry version.
- [x] I have searched the [issues](https://github.com/sdispater/poetry/issues) of this repo and believe that this is not a duplicate.
- [x] If an exception occurs when executing a command, I executed it again in debug mode (`-vvv` option).

<!--
  Once those are done, if you're able to fill in the following list with your information,
  it'd be very helpful to whoever handles the issue.
-->

- **OS version and name**: macOS 10.14.6 (18G103)
- **Poetry version**: <!-- 1.0.0b5
- **Link of a [Gist](https://gist.github.com/) with the contents of your pyproject.toml file**: <!-- Gist Link Here --> https://gist.github.com/JBKahn/4bbb040c0181d974e0b71407ad764b6c


## Issue
When moving from `1.0.0b4` to `1.0.0b5` `poetry lock` is removing the 
```
[package.source]
reference = "private"
type = "legacy"
url = "https://private.url"
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `poetry/packages/locker.py`
Content:
```
1 import json
2 import re
3 
4 from hashlib import sha256
5 from typing import List
6 
7 from tomlkit import document
8 from tomlkit import inline_table
9 from tomlkit import item
10 from tomlkit import table
11 from tomlkit.exceptions import TOMLKitError
12 
13 import poetry.packages
14 import poetry.repositories
15 
16 from poetry.utils._compat import Path
17 from poetry.utils.toml_file import TomlFile
18 from poetry.version.markers import parse_marker
19 
20 
21 class Locker(object):
22 
23     _relevant_keys = ["dependencies", "dev-dependencies", "source", "extras"]
24 
25     def __init__(self, lock, local_config):  # type: (Path, dict) -> None
26         self._lock = TomlFile(lock)
27         self._local_config = local_config
28         self._lock_data = None
29         self._content_hash = self._get_content_hash()
30 
31     @property
32     def lock(self):  # type: () -> TomlFile
33         return self._lock
34 
35     @property
36     def lock_data(self):
37         if self._lock_data is None:
38             self._lock_data = self._get_lock_data()
39 
40         return self._lock_data
41 
42     def is_locked(self):  # type: () -> bool
43         """
44         Checks whether the locker has been locked (lockfile found).
45         """
46         if not self._lock.exists():
47             return False
48 
49         return "package" in self.lock_data
50 
51     def is_fresh(self):  # type: () -> bool
52         """
53         Checks whether the lock file is still up to date with the current hash.
54         """
55         lock = self._lock.read()
56         metadata = lock.get("metadata", {})
57 
58         if "content-hash" in metadata:
59             return self._content_hash == lock["metadata"]["content-hash"]
60 
61         return False
62 
63     def locked_repository(
64         self, with_dev_reqs=False
65     ):  # type: (bool) -> poetry.repositories.Repository
66         """
67         Searches and returns a repository of locked packages.
68         """
69         if not self.is_locked():
70             return poetry.repositories.Repository()
71 
72         lock_data = self.lock_data
73         packages = poetry.repositories.Repository()
74 
75         if with_dev_reqs:
76             locked_packages = lock_data["package"]
77         else:
78             locked_packages = [
79                 p for p in lock_data["package"] if p["category"] == "main"
80             ]
81 
82         if not locked_packages:
83             return packages
84 
85         for info in locked_packages:
86             package = poetry.packages.Package(
87                 info["name"], info["version"], info["version"]
88             )
89             package.description = info.get("description", "")
90             package.category = info["category"]
91             package.optional = info["optional"]
92             if "hashes" in lock_data["metadata"]:
93                 # Old lock so we create dummy files from the hashes
94                 package.files = [
95                     {"name": h, "hash": h}
96                     for h in lock_data["metadata"]["hashes"][info["name"]]
97                 ]
98             else:
99                 package.files = lock_data["metadata"]["files"][info["name"]]
100 
101             package.python_versions = info["python-versions"]
102             extras = info.get("extras", {})
103             if extras:
104                 for name, deps in extras.items():
105                     package.extras[name] = []
106 
107                     for dep in deps:
108                         m = re.match(r"^(.+?)(?:\s+\((.+)\))?$", dep)
109                         dep_name = m.group(1)
110                         constraint = m.group(2) or "*"
111 
112                         package.extras[name].append(
113                             poetry.packages.Dependency(dep_name, constraint)
114                         )
115 
116             if "marker" in info:
117                 package.marker = parse_marker(info["marker"])
118             else:
119                 # Compatibility for old locks
120                 if "requirements" in info:
121                     dep = poetry.packages.Dependency("foo", "0.0.0")
122                     for name, value in info["requirements"].items():
123                         if name == "python":
124                             dep.python_versions = value
125                         elif name == "platform":
126                             dep.platform = value
127 
128                     split_dep = dep.to_pep_508(False).split(";")
129                     if len(split_dep) > 1:
130                         package.marker = parse_marker(split_dep[1].strip())
131 
132             for dep_name, constraint in info.get("dependencies", {}).items():
133                 if isinstance(constraint, list):
134                     for c in constraint:
135                         package.add_dependency(dep_name, c)
136 
137                     continue
138 
139                 package.add_dependency(dep_name, constraint)
140 
141             if "source" in info:
142                 package.source_type = info["source"]["type"]
143                 package.source_url = info["source"]["url"]
144                 package.source_reference = info["source"]["reference"]
145 
146             packages.add_package(package)
147 
148         return packages
149 
150     def set_lock_data(self, root, packages):  # type: (...) -> bool
151         files = table()
152         packages = self._lock_packages(packages)
153         # Retrieving hashes
154         for package in packages:
155             if package["name"] not in files:
156                 files[package["name"]] = []
157 
158             for f in package["files"]:
159                 file_metadata = inline_table()
160                 for k, v in sorted(f.items()):
161                     file_metadata[k] = v
162 
163                 files[package["name"]].append(file_metadata)
164 
165             if files[package["name"]]:
166                 files[package["name"]] = item(files[package["name"]]).multiline(True)
167 
168             del package["files"]
169 
170         lock = document()
171         lock["package"] = packages
172 
173         if root.extras:
174             lock["extras"] = {
175                 extra: [dep.pretty_name for dep in deps]
176                 for extra, deps in root.extras.items()
177             }
178 
179         lock["metadata"] = {
180             "python-versions": root.python_versions,
181             "content-hash": self._content_hash,
182             "files": files,
183         }
184 
185         if not self.is_locked() or lock != self.lock_data:
186             self._write_lock_data(lock)
187 
188             return True
189 
190         return False
191 
192     def _write_lock_data(self, data):
193         self.lock.write(data)
194 
195         # Checking lock file data consistency
196         if data != self.lock.read():
197             raise RuntimeError("Inconsistent lock file data.")
198 
199         self._lock_data = None
200 
201     def _get_content_hash(self):  # type: () -> str
202         """
203         Returns the sha256 hash of the sorted content of the pyproject file.
204         """
205         content = self._local_config
206 
207         relevant_content = {}
208         for key in self._relevant_keys:
209             relevant_content[key] = content.get(key)
210 
211         content_hash = sha256(
212             json.dumps(relevant_content, sort_keys=True).encode()
213         ).hexdigest()
214 
215         return content_hash
216 
217     def _get_lock_data(self):  # type: () -> dict
218         if not self._lock.exists():
219             raise RuntimeError("No lockfile found. Unable to read locked packages")
220 
221         try:
222             return self._lock.read()
223         except TOMLKitError as e:
224             raise RuntimeError("Unable to read the lock file ({}).".format(e))
225 
226     def _lock_packages(
227         self, packages
228     ):  # type: (List['poetry.packages.Package']) -> list
229         locked = []
230 
231         for package in sorted(packages, key=lambda x: x.name):
232             spec = self._dump_package(package)
233 
234             locked.append(spec)
235 
236         return locked
237 
238     def _dump_package(self, package):  # type: (poetry.packages.Package) -> dict
239         dependencies = {}
240         for dependency in sorted(package.requires, key=lambda d: d.name):
241             if dependency.is_optional() and not dependency.is_activated():
242                 continue
243 
244             if dependency.pretty_name not in dependencies:
245                 dependencies[dependency.pretty_name] = []
246 
247             constraint = {"version": str(dependency.pretty_constraint)}
248 
249             if dependency.extras:
250                 constraint["extras"] = dependency.extras
251 
252             if dependency.is_optional():
253                 constraint["optional"] = True
254 
255             if not dependency.python_constraint.is_any():
256                 constraint["python"] = str(dependency.python_constraint)
257 
258             dependencies[dependency.pretty_name].append(constraint)
259 
260         # All the constraints should have the same type,
261         # but we want to simplify them if it's possible
262         for dependency, constraints in tuple(dependencies.items()):
263             if all(len(constraint) == 1 for constraint in constraints):
264                 dependencies[dependency] = [
265                     constraint["version"] for constraint in constraints
266                 ]
267 
268         data = {
269             "name": package.pretty_name,
270             "version": package.pretty_version,
271             "description": package.description or "",
272             "category": package.category,
273             "optional": package.optional,
274             "python-versions": package.python_versions,
275             "files": sorted(package.files, key=lambda x: x["file"]),
276         }
277         if not package.marker.is_any():
278             data["marker"] = str(package.marker)
279 
280         if package.extras:
281             extras = {}
282             for name, deps in package.extras.items():
283                 extras[name] = [
284                     str(dep) if not dep.constraint.is_any() else dep.name
285                     for dep in deps
286                 ]
287 
288             data["extras"] = extras
289 
290         if dependencies:
291             for k, constraints in dependencies.items():
292                 if len(constraints) == 1:
293                     dependencies[k] = constraints[0]
294 
295             data["dependencies"] = dependencies
296 
297         if package.source_type:
298             data["source"] = {
299                 "type": package.source_type,
300                 "url": package.source_url,
301                 "reference": package.source_reference,
302             }
303 
304         return data
305
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/poetry/packages/locker.py b/poetry/packages/locker.py
--- a/poetry/packages/locker.py
+++ b/poetry/packages/locker.py
@@ -139,7 +139,7 @@
                 package.add_dependency(dep_name, constraint)
 
             if "source" in info:
-                package.source_type = info["source"]["type"]
+                package.source_type = info["source"].get("type", "")
                 package.source_url = info["source"]["url"]
                 package.source_reference = info["source"]["reference"]
 
@@ -294,11 +294,12 @@
 
             data["dependencies"] = dependencies
 
-        if package.source_type:
+        if package.source_url:
             data["source"] = {
-                "type": package.source_type,
                 "url": package.source_url,
                 "reference": package.source_reference,
             }
+            if package.source_type:
+                data["source"]["type"] = package.source_type
 
         return data

{"golden_diff": "diff --git a/poetry/packages/locker.py b/poetry/packages/locker.py\n--- a/poetry/packages/locker.py\n+++ b/poetry/packages/locker.py\n@@ -139,7 +139,7 @@\n                 package.add_dependency(dep_name, constraint)\n \n             if \"source\" in info:\n-                package.source_type = info[\"source\"][\"type\"]\n+                package.source_type = info[\"source\"].get(\"type\", \"\")\n                 package.source_url = info[\"source\"][\"url\"]\n                 package.source_reference = info[\"source\"][\"reference\"]\n \n@@ -294,11 +294,12 @@\n \n             data[\"dependencies\"] = dependencies\n \n-        if package.source_type:\n+        if package.source_url:\n             data[\"source\"] = {\n-                \"type\": package.source_type,\n                 \"url\": package.source_url,\n                 \"reference\": package.source_reference,\n             }\n+            if package.source_type:\n+                data[\"source\"][\"type\"] = package.source_type\n \n         return data\n", "issue": "1.0.0b5 removes my private source from the lockfile\n<!--\r\n  Hi there! Thank you for discovering and submitting an issue.\r\n\r\n  Before you submit this; let's make sure of a few things.\r\n  Please make sure the following boxes are ticked if they are correct.\r\n  If not, please try and fulfill these first.\r\n-->\r\n\r\n<!-- Checked checkbox should look like this: [x] -->\r\n- [x] I am on the [latest](https://github.com/sdispater/poetry/releases/latest) Poetry version.\r\n- [x] I have searched the [issues](https://github.com/sdispater/poetry/issues) of this repo and believe that this is not a duplicate.\r\n- [x] If an exception occurs when executing a command, I executed it again in debug mode (`-vvv` option).\r\n\r\n<!--\r\n  Once those are done, if you're able to fill in the following list with your information,\r\n  it'd be very helpful to whoever handles the issue.\r\n-->\r\n\r\n- **OS version and name**: macOS 10.14.6 (18G103)\r\n- **Poetry version**: <!-- 1.0.0b5\r\n- **Link of a [Gist](https://gist.github.com/) with the contents of your pyproject.toml file**: <!-- Gist Link Here --> https://gist.github.com/JBKahn/4bbb040c0181d974e0b71407ad764b6c\r\n\r\n\r\n## Issue\r\nWhen moving from `1.0.0b4` to `1.0.0b5` `poetry lock` is removing the \r\n```\r\n[package.source]\r\nreference = \"private\"\r\ntype = \"legacy\"\r\nurl = \"https://private.url\"\r\n```\r\n\n", "before_files": [{"content": "import json\nimport re\n\nfrom hashlib import sha256\nfrom typing import List\n\nfrom tomlkit import document\nfrom tomlkit import inline_table\nfrom tomlkit import item\nfrom tomlkit import table\nfrom tomlkit.exceptions import TOMLKitError\n\nimport poetry.packages\nimport poetry.repositories\n\nfrom poetry.utils._compat import Path\nfrom poetry.utils.toml_file import TomlFile\nfrom poetry.version.markers import parse_marker\n\n\nclass Locker(object):\n\n    _relevant_keys = [\"dependencies\", \"dev-dependencies\", \"source\", \"extras\"]\n\n    def __init__(self, lock, local_config):  # type: (Path, dict) -> None\n        self._lock = TomlFile(lock)\n        self._local_config = local_config\n        self._lock_data = None\n        self._content_hash = self._get_content_hash()\n\n    @property\n    def lock(self):  # type: () -> TomlFile\n        return self._lock\n\n    @property\n    def lock_data(self):\n        if self._lock_data is None:\n            self._lock_data = self._get_lock_data()\n\n        return self._lock_data\n\n    def is_locked(self):  # type: () -> bool\n        \"\"\"\n        Checks whether the locker has been locked (lockfile found).\n        \"\"\"\n        if not self._lock.exists():\n            return False\n\n        return \"package\" in self.lock_data\n\n    def is_fresh(self):  # type: () -> bool\n        \"\"\"\n        Checks whether the lock file is still up to date with the current hash.\n        \"\"\"\n        lock = self._lock.read()\n        metadata = lock.get(\"metadata\", {})\n\n        if \"content-hash\" in metadata:\n            return self._content_hash == lock[\"metadata\"][\"content-hash\"]\n\n        return False\n\n    def locked_repository(\n        self, with_dev_reqs=False\n    ):  # type: (bool) -> poetry.repositories.Repository\n        \"\"\"\n        Searches and returns a repository of locked packages.\n        \"\"\"\n        if not self.is_locked():\n            return poetry.repositories.Repository()\n\n        lock_data = self.lock_data\n        packages = poetry.repositories.Repository()\n\n        if with_dev_reqs:\n            locked_packages = lock_data[\"package\"]\n        else:\n            locked_packages = [\n                p for p in lock_data[\"package\"] if p[\"category\"] == \"main\"\n            ]\n\n        if not locked_packages:\n            return packages\n\n        for info in locked_packages:\n            package = poetry.packages.Package(\n                info[\"name\"], info[\"version\"], info[\"version\"]\n            )\n            package.description = info.get(\"description\", \"\")\n            package.category = info[\"category\"]\n            package.optional = info[\"optional\"]\n            if \"hashes\" in lock_data[\"metadata\"]:\n                # Old lock so we create dummy files from the hashes\n                package.files = [\n                    {\"name\": h, \"hash\": h}\n                    for h in lock_data[\"metadata\"][\"hashes\"][info[\"name\"]]\n                ]\n            else:\n                package.files = lock_data[\"metadata\"][\"files\"][info[\"name\"]]\n\n            package.python_versions = info[\"python-versions\"]\n            extras = info.get(\"extras\", {})\n            if extras:\n                for name, deps in extras.items():\n                    package.extras[name] = []\n\n                    for dep in deps:\n                        m = re.match(r\"^(.+?)(?:\\s+\\((.+)\\))?$\", dep)\n                        dep_name = m.group(1)\n                        constraint = m.group(2) or \"*\"\n\n                        package.extras[name].append(\n                            poetry.packages.Dependency(dep_name, constraint)\n                        )\n\n            if \"marker\" in info:\n                package.marker = parse_marker(info[\"marker\"])\n            else:\n                # Compatibility for old locks\n                if \"requirements\" in info:\n                    dep = poetry.packages.Dependency(\"foo\", \"0.0.0\")\n                    for name, value in info[\"requirements\"].items():\n                        if name == \"python\":\n                            dep.python_versions = value\n                        elif name == \"platform\":\n                            dep.platform = value\n\n                    split_dep = dep.to_pep_508(False).split(\";\")\n                    if len(split_dep) > 1:\n                        package.marker = parse_marker(split_dep[1].strip())\n\n            for dep_name, constraint in info.get(\"dependencies\", {}).items():\n                if isinstance(constraint, list):\n                    for c in constraint:\n                        package.add_dependency(dep_name, c)\n\n                    continue\n\n                package.add_dependency(dep_name, constraint)\n\n            if \"source\" in info:\n                package.source_type = info[\"source\"][\"type\"]\n                package.source_url = info[\"source\"][\"url\"]\n                package.source_reference = info[\"source\"][\"reference\"]\n\n            packages.add_package(package)\n\n        return packages\n\n    def set_lock_data(self, root, packages):  # type: (...) -> bool\n        files = table()\n        packages = self._lock_packages(packages)\n        # Retrieving hashes\n        for package in packages:\n            if package[\"name\"] not in files:\n                files[package[\"name\"]] = []\n\n            for f in package[\"files\"]:\n                file_metadata = inline_table()\n                for k, v in sorted(f.items()):\n                    file_metadata[k] = v\n\n                files[package[\"name\"]].append(file_metadata)\n\n            if files[package[\"name\"]]:\n                files[package[\"name\"]] = item(files[package[\"name\"]]).multiline(True)\n\n            del package[\"files\"]\n\n        lock = document()\n        lock[\"package\"] = packages\n\n        if root.extras:\n            lock[\"extras\"] = {\n                extra: [dep.pretty_name for dep in deps]\n                for extra, deps in root.extras.items()\n            }\n\n        lock[\"metadata\"] = {\n            \"python-versions\": root.python_versions,\n            \"content-hash\": self._content_hash,\n            \"files\": files,\n        }\n\n        if not self.is_locked() or lock != self.lock_data:\n            self._write_lock_data(lock)\n\n            return True\n\n        return False\n\n    def _write_lock_data(self, data):\n        self.lock.write(data)\n\n        # Checking lock file data consistency\n        if data != self.lock.read():\n            raise RuntimeError(\"Inconsistent lock file data.\")\n\n        self._lock_data = None\n\n    def _get_content_hash(self):  # type: () -> str\n        \"\"\"\n        Returns the sha256 hash of the sorted content of the pyproject file.\n        \"\"\"\n        content = self._local_config\n\n        relevant_content = {}\n        for key in self._relevant_keys:\n            relevant_content[key] = content.get(key)\n\n        content_hash = sha256(\n            json.dumps(relevant_content, sort_keys=True).encode()\n        ).hexdigest()\n\n        return content_hash\n\n    def _get_lock_data(self):  # type: () -> dict\n        if not self._lock.exists():\n            raise RuntimeError(\"No lockfile found. Unable to read locked packages\")\n\n        try:\n            return self._lock.read()\n        except TOMLKitError as e:\n            raise RuntimeError(\"Unable to read the lock file ({}).\".format(e))\n\n    def _lock_packages(\n        self, packages\n    ):  # type: (List['poetry.packages.Package']) -> list\n        locked = []\n\n        for package in sorted(packages, key=lambda x: x.name):\n            spec = self._dump_package(package)\n\n            locked.append(spec)\n\n        return locked\n\n    def _dump_package(self, package):  # type: (poetry.packages.Package) -> dict\n        dependencies = {}\n        for dependency in sorted(package.requires, key=lambda d: d.name):\n            if dependency.is_optional() and not dependency.is_activated():\n                continue\n\n            if dependency.pretty_name not in dependencies:\n                dependencies[dependency.pretty_name] = []\n\n            constraint = {\"version\": str(dependency.pretty_constraint)}\n\n            if dependency.extras:\n                constraint[\"extras\"] = dependency.extras\n\n            if dependency.is_optional():\n                constraint[\"optional\"] = True\n\n            if not dependency.python_constraint.is_any():\n                constraint[\"python\"] = str(dependency.python_constraint)\n\n            dependencies[dependency.pretty_name].append(constraint)\n\n        # All the constraints should have the same type,\n        # but we want to simplify them if it's possible\n        for dependency, constraints in tuple(dependencies.items()):\n            if all(len(constraint) == 1 for constraint in constraints):\n                dependencies[dependency] = [\n                    constraint[\"version\"] for constraint in constraints\n                ]\n\n        data = {\n            \"name\": package.pretty_name,\n            \"version\": package.pretty_version,\n            \"description\": package.description or \"\",\n            \"category\": package.category,\n            \"optional\": package.optional,\n            \"python-versions\": package.python_versions,\n            \"files\": sorted(package.files, key=lambda x: x[\"file\"]),\n        }\n        if not package.marker.is_any():\n            data[\"marker\"] = str(package.marker)\n\n        if package.extras:\n            extras = {}\n            for name, deps in package.extras.items():\n                extras[name] = [\n                    str(dep) if not dep.constraint.is_any() else dep.name\n                    for dep in deps\n                ]\n\n            data[\"extras\"] = extras\n\n        if dependencies:\n            for k, constraints in dependencies.items():\n                if len(constraints) == 1:\n                    dependencies[k] = constraints[0]\n\n            data[\"dependencies\"] = dependencies\n\n        if package.source_type:\n            data[\"source\"] = {\n                \"type\": package.source_type,\n                \"url\": package.source_url,\n                \"reference\": package.source_reference,\n            }\n\n        return data\n", "path": "poetry/packages/locker.py"}], "after_files": [{"content": "import json\nimport re\n\nfrom hashlib import sha256\nfrom typing import List\n\nfrom tomlkit import document\nfrom tomlkit import inline_table\nfrom tomlkit import item\nfrom tomlkit import table\nfrom tomlkit.exceptions import TOMLKitError\n\nimport poetry.packages\nimport poetry.repositories\n\nfrom poetry.utils._compat import Path\nfrom poetry.utils.toml_file import TomlFile\nfrom poetry.version.markers import parse_marker\n\n\nclass Locker(object):\n\n    _relevant_keys = [\"dependencies\", \"dev-dependencies\", \"source\", \"extras\"]\n\n    def __init__(self, lock, local_config):  # type: (Path, dict) -> None\n        self._lock = TomlFile(lock)\n        self._local_config = local_config\n        self._lock_data = None\n        self._content_hash = self._get_content_hash()\n\n    @property\n    def lock(self):  # type: () -> TomlFile\n        return self._lock\n\n    @property\n    def lock_data(self):\n        if self._lock_data is None:\n            self._lock_data = self._get_lock_data()\n\n        return self._lock_data\n\n    def is_locked(self):  # type: () -> bool\n        \"\"\"\n        Checks whether the locker has been locked (lockfile found).\n        \"\"\"\n        if not self._lock.exists():\n            return False\n\n        return \"package\" in self.lock_data\n\n    def is_fresh(self):  # type: () -> bool\n        \"\"\"\n        Checks whether the lock file is still up to date with the current hash.\n        \"\"\"\n        lock = self._lock.read()\n        metadata = lock.get(\"metadata\", {})\n\n        if \"content-hash\" in metadata:\n            return self._content_hash == lock[\"metadata\"][\"content-hash\"]\n\n        return False\n\n    def locked_repository(\n        self, with_dev_reqs=False\n    ):  # type: (bool) -> poetry.repositories.Repository\n        \"\"\"\n        Searches and returns a repository of locked packages.\n        \"\"\"\n        if not self.is_locked():\n            return poetry.repositories.Repository()\n\n        lock_data = self.lock_data\n        packages = poetry.repositories.Repository()\n\n        if with_dev_reqs:\n            locked_packages = lock_data[\"package\"]\n        else:\n            locked_packages = [\n                p for p in lock_data[\"package\"] if p[\"category\"] == \"main\"\n            ]\n\n        if not locked_packages:\n            return packages\n\n        for info in locked_packages:\n            package = poetry.packages.Package(\n                info[\"name\"], info[\"version\"], info[\"version\"]\n            )\n            package.description = info.get(\"description\", \"\")\n            package.category = info[\"category\"]\n            package.optional = info[\"optional\"]\n            if \"hashes\" in lock_data[\"metadata\"]:\n                # Old lock so we create dummy files from the hashes\n                package.files = [\n                    {\"name\": h, \"hash\": h}\n                    for h in lock_data[\"metadata\"][\"hashes\"][info[\"name\"]]\n                ]\n            else:\n                package.files = lock_data[\"metadata\"][\"files\"][info[\"name\"]]\n\n            package.python_versions = info[\"python-versions\"]\n            extras = info.get(\"extras\", {})\n            if extras:\n                for name, deps in extras.items():\n                    package.extras[name] = []\n\n                    for dep in deps:\n                        m = re.match(r\"^(.+?)(?:\\s+\\((.+)\\))?$\", dep)\n                        dep_name = m.group(1)\n                        constraint = m.group(2) or \"*\"\n\n                        package.extras[name].append(\n                            poetry.packages.Dependency(dep_name, constraint)\n                        )\n\n            if \"marker\" in info:\n                package.marker = parse_marker(info[\"marker\"])\n            else:\n                # Compatibility for old locks\n                if \"requirements\" in info:\n                    dep = poetry.packages.Dependency(\"foo\", \"0.0.0\")\n                    for name, value in info[\"requirements\"].items():\n                        if name == \"python\":\n                            dep.python_versions = value\n                        elif name == \"platform\":\n                            dep.platform = value\n\n                    split_dep = dep.to_pep_508(False).split(\";\")\n                    if len(split_dep) > 1:\n                        package.marker = parse_marker(split_dep[1].strip())\n\n            for dep_name, constraint in info.get(\"dependencies\", {}).items():\n                if isinstance(constraint, list):\n                    for c in constraint:\n                        package.add_dependency(dep_name, c)\n\n                    continue\n\n                package.add_dependency(dep_name, constraint)\n\n            if \"source\" in info:\n                package.source_type = info[\"source\"].get(\"type\", \"\")\n                package.source_url = info[\"source\"][\"url\"]\n                package.source_reference = info[\"source\"][\"reference\"]\n\n            packages.add_package(package)\n\n        return packages\n\n    def set_lock_data(self, root, packages):  # type: (...) -> bool\n        files = table()\n        packages = self._lock_packages(packages)\n        # Retrieving hashes\n        for package in packages:\n            if package[\"name\"] not in files:\n                files[package[\"name\"]] = []\n\n            for f in package[\"files\"]:\n                file_metadata = inline_table()\n                for k, v in sorted(f.items()):\n                    file_metadata[k] = v\n\n                files[package[\"name\"]].append(file_metadata)\n\n            if files[package[\"name\"]]:\n                files[package[\"name\"]] = item(files[package[\"name\"]]).multiline(True)\n\n            del package[\"files\"]\n\n        lock = document()\n        lock[\"package\"] = packages\n\n        if root.extras:\n            lock[\"extras\"] = {\n                extra: [dep.pretty_name for dep in deps]\n                for extra, deps in root.extras.items()\n            }\n\n        lock[\"metadata\"] = {\n            \"python-versions\": root.python_versions,\n            \"content-hash\": self._content_hash,\n            \"files\": files,\n        }\n\n        if not self.is_locked() or lock != self.lock_data:\n            self._write_lock_data(lock)\n\n            return True\n\n        return False\n\n    def _write_lock_data(self, data):\n        self.lock.write(data)\n\n        # Checking lock file data consistency\n        if data != self.lock.read():\n            raise RuntimeError(\"Inconsistent lock file data.\")\n\n        self._lock_data = None\n\n    def _get_content_hash(self):  # type: () -> str\n        \"\"\"\n        Returns the sha256 hash of the sorted content of the pyproject file.\n        \"\"\"\n        content = self._local_config\n\n        relevant_content = {}\n        for key in self._relevant_keys:\n            relevant_content[key] = content.get(key)\n\n        content_hash = sha256(\n            json.dumps(relevant_content, sort_keys=True).encode()\n        ).hexdigest()\n\n        return content_hash\n\n    def _get_lock_data(self):  # type: () -> dict\n        if not self._lock.exists():\n            raise RuntimeError(\"No lockfile found. Unable to read locked packages\")\n\n        try:\n            return self._lock.read()\n        except TOMLKitError as e:\n            raise RuntimeError(\"Unable to read the lock file ({}).\".format(e))\n\n    def _lock_packages(\n        self, packages\n    ):  # type: (List['poetry.packages.Package']) -> list\n        locked = []\n\n        for package in sorted(packages, key=lambda x: x.name):\n            spec = self._dump_package(package)\n\n            locked.append(spec)\n\n        return locked\n\n    def _dump_package(self, package):  # type: (poetry.packages.Package) -> dict\n        dependencies = {}\n        for dependency in sorted(package.requires, key=lambda d: d.name):\n            if dependency.is_optional() and not dependency.is_activated():\n                continue\n\n            if dependency.pretty_name not in dependencies:\n                dependencies[dependency.pretty_name] = []\n\n            constraint = {\"version\": str(dependency.pretty_constraint)}\n\n            if dependency.extras:\n                constraint[\"extras\"] = dependency.extras\n\n            if dependency.is_optional():\n                constraint[\"optional\"] = True\n\n            if not dependency.python_constraint.is_any():\n                constraint[\"python\"] = str(dependency.python_constraint)\n\n            dependencies[dependency.pretty_name].append(constraint)\n\n        # All the constraints should have the same type,\n        # but we want to simplify them if it's possible\n        for dependency, constraints in tuple(dependencies.items()):\n            if all(len(constraint) == 1 for constraint in constraints):\n                dependencies[dependency] = [\n                    constraint[\"version\"] for constraint in constraints\n                ]\n\n        data = {\n            \"name\": package.pretty_name,\n            \"version\": package.pretty_version,\n            \"description\": package.description or \"\",\n            \"category\": package.category,\n            \"optional\": package.optional,\n            \"python-versions\": package.python_versions,\n            \"files\": sorted(package.files, key=lambda x: x[\"file\"]),\n        }\n        if not package.marker.is_any():\n            data[\"marker\"] = str(package.marker)\n\n        if package.extras:\n            extras = {}\n            for name, deps in package.extras.items():\n                extras[name] = [\n                    str(dep) if not dep.constraint.is_any() else dep.name\n                    for dep in deps\n                ]\n\n            data[\"extras\"] = extras\n\n        if dependencies:\n            for k, constraints in dependencies.items():\n                if len(constraints) == 1:\n                    dependencies[k] = constraints[0]\n\n            data[\"dependencies\"] = dependencies\n\n        if package.source_url:\n            data[\"source\"] = {\n                \"url\": package.source_url,\n                \"reference\": package.source_reference,\n            }\n            if package.source_type:\n                data[\"source\"][\"type\"] = package.source_type\n\n        return data\n", "path": "poetry/packages/locker.py"}]}