Skip to content

Commit b42095d

Browse files
committed
Implement PEP 752
1 parent bd56b0b commit b42095d

File tree

22 files changed

+954
-61
lines changed

22 files changed

+954
-61
lines changed

tests/common/db/organizations.py

+17
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414

1515
import factory
1616
import faker
17+
import packaging.utils
1718

1819
from warehouse.organizations.models import (
20+
Namespace,
1921
Organization,
2022
OrganizationApplication,
2123
OrganizationInvitation,
@@ -186,3 +188,18 @@ class Meta:
186188
role_name = TeamProjectRoleType.Owner
187189
project = factory.SubFactory(ProjectFactory)
188190
team = factory.SubFactory(TeamFactory)
191+
192+
193+
class NamespaceFactory(WarehouseFactory):
194+
class Meta:
195+
model = Namespace
196+
197+
is_approved = True
198+
created = factory.Faker(
199+
"date_time_between_dates", datetime_start=datetime.datetime(2008, 1, 1)
200+
)
201+
name = factory.Faker("pystr", max_chars=12)
202+
normalized_name = factory.LazyAttribute(
203+
lambda o: packaging.utils.canonicalize_name(o.name)
204+
)
205+
owner = factory.SubFactory(OrganizationFactory)

tests/unit/api/test_simple.py

+97
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
from warehouse.packaging.utils import API_VERSION, _valid_simple_detail_context
2323

2424
from ...common.db.accounts import UserFactory
25+
from ...common.db.organizations import (
26+
NamespaceFactory,
27+
OrganizationFactory,
28+
OrganizationProjectFactory,
29+
)
2530
from ...common.db.packaging import (
2631
AlternateRepositoryFactory,
2732
FileFactory,
@@ -221,6 +226,7 @@ def test_no_files_no_serial(self, db_request, content_type, renderer_override):
221226
"files": [],
222227
"versions": [],
223228
"alternate-locations": [],
229+
"namespace": None,
224230
}
225231
context = _update_context(context, content_type, renderer_override)
226232
assert simple.simple_detail(project, db_request) == context
@@ -253,6 +259,92 @@ def test_no_files_with_serial(self, db_request, content_type, renderer_override)
253259
"files": [],
254260
"versions": [],
255261
"alternate-locations": sorted(al.url for al in als),
262+
"namespace": None,
263+
}
264+
context = _update_context(context, content_type, renderer_override)
265+
assert simple.simple_detail(project, db_request) == context
266+
267+
assert db_request.response.headers["X-PyPI-Last-Serial"] == str(je.id)
268+
assert db_request.response.content_type == content_type
269+
_assert_has_cors_headers(db_request.response.headers)
270+
271+
if renderer_override is not None:
272+
assert db_request.override_renderer == renderer_override
273+
274+
@pytest.mark.parametrize(
275+
("content_type", "renderer_override"),
276+
CONTENT_TYPE_PARAMS,
277+
)
278+
def test_with_namespaces_authorized(
279+
self, db_request, content_type, renderer_override
280+
):
281+
db_request.accept = content_type
282+
org = OrganizationFactory.create()
283+
namespace = NamespaceFactory.create(owner=org)
284+
project = ProjectFactory.create(name=f"{namespace.name}-foo")
285+
OrganizationProjectFactory.create(organization=org, project=project)
286+
db_request.matchdict["name"] = project.normalized_name
287+
user = UserFactory.create()
288+
je = JournalEntryFactory.create(name=project.name, submitted_by=user)
289+
als = [
290+
AlternateRepositoryFactory.create(project=project),
291+
AlternateRepositoryFactory.create(project=project),
292+
]
293+
294+
context = {
295+
"meta": {"_last-serial": je.id, "api-version": API_VERSION},
296+
"name": project.normalized_name,
297+
"files": [],
298+
"versions": [],
299+
"alternate-locations": sorted(al.url for al in als),
300+
"namespace": {
301+
"prefix": namespace.normalized_name,
302+
"open": namespace.is_open,
303+
"authorized": True,
304+
},
305+
}
306+
context = _update_context(context, content_type, renderer_override)
307+
assert simple.simple_detail(project, db_request) == context
308+
309+
assert db_request.response.headers["X-PyPI-Last-Serial"] == str(je.id)
310+
assert db_request.response.content_type == content_type
311+
_assert_has_cors_headers(db_request.response.headers)
312+
313+
if renderer_override is not None:
314+
assert db_request.override_renderer == renderer_override
315+
316+
@pytest.mark.parametrize(
317+
("content_type", "renderer_override"),
318+
CONTENT_TYPE_PARAMS,
319+
)
320+
def test_with_namespaces_not_authorized(
321+
self, db_request, content_type, renderer_override
322+
):
323+
db_request.accept = content_type
324+
org = OrganizationFactory.create()
325+
namespace = NamespaceFactory.create(owner=org)
326+
project = ProjectFactory.create(name=f"{namespace.name}-foo")
327+
project2 = ProjectFactory.create(name=f"{namespace.name}-foo2")
328+
OrganizationProjectFactory.create(organization=org, project=project2)
329+
db_request.matchdict["name"] = project.normalized_name
330+
user = UserFactory.create()
331+
je = JournalEntryFactory.create(name=project.name, submitted_by=user)
332+
als = [
333+
AlternateRepositoryFactory.create(project=project),
334+
AlternateRepositoryFactory.create(project=project),
335+
]
336+
337+
context = {
338+
"meta": {"_last-serial": je.id, "api-version": API_VERSION},
339+
"name": project.normalized_name,
340+
"files": [],
341+
"versions": [],
342+
"alternate-locations": sorted(al.url for al in als),
343+
"namespace": {
344+
"prefix": namespace.normalized_name,
345+
"open": namespace.is_open,
346+
"authorized": False,
347+
},
256348
}
257349
context = _update_context(context, content_type, renderer_override)
258350
assert simple.simple_detail(project, db_request) == context
@@ -305,6 +397,7 @@ def test_with_files_no_serial(self, db_request, content_type, renderer_override)
305397
for f in files
306398
],
307399
"alternate-locations": [],
400+
"namespace": None,
308401
}
309402
context = _update_context(context, content_type, renderer_override)
310403
assert simple.simple_detail(project, db_request) == context
@@ -357,6 +450,7 @@ def test_with_files_with_serial(self, db_request, content_type, renderer_overrid
357450
for f in files
358451
],
359452
"alternate-locations": [],
453+
"namespace": None,
360454
}
361455
context = _update_context(context, content_type, renderer_override)
362456
assert simple.simple_detail(project, db_request) == context
@@ -454,6 +548,7 @@ def test_with_files_with_version_multi_digit(
454548
for f in files
455549
],
456550
"alternate-locations": [],
551+
"namespace": None,
457552
}
458553
context = _update_context(context, content_type, renderer_override)
459554
assert simple.simple_detail(project, db_request) == context
@@ -486,6 +581,7 @@ def test_with_files_quarantined_omitted_from_index(
486581
"files": [],
487582
"versions": [],
488583
"alternate-locations": [],
584+
"namespace": None,
489585
}
490586
context = _update_context(context, content_type, renderer_override)
491587

@@ -606,6 +702,7 @@ def route_url(route, **kw):
606702
for f in files
607703
],
608704
"alternate-locations": [],
705+
"namespace": None,
609706
}
610707
context = _update_context(context, content_type, renderer_override)
611708

tests/unit/organizations/test_init.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515
from celery.schedules import crontab
1616

1717
from warehouse import organizations
18-
from warehouse.organizations.interfaces import IOrganizationService
19-
from warehouse.organizations.services import database_organization_factory
18+
from warehouse.organizations.interfaces import INamespaceService, IOrganizationService
19+
from warehouse.organizations.services import (
20+
database_namespace_factory,
21+
database_organization_factory,
22+
)
2023
from warehouse.organizations.tasks import (
2124
delete_declined_organizations,
2225
update_organization_invitation_status,
@@ -36,6 +39,7 @@ def test_includeme():
3639

3740
assert config.register_service_factory.calls == [
3841
pretend.call(database_organization_factory, IOrganizationService),
42+
pretend.call(database_namespace_factory, INamespaceService),
3943
]
4044

4145
assert config.add_periodic_task.calls == [

0 commit comments

Comments
 (0)