By continuing you indicate that you have read and agree to our Terms of service and Privacy policy
By continuing you indicate that you have read and agree to our Terms of service and Privacy policy
Popular Releases
Popular Libraries
New Libraries
Top Authors
Trending Kits
Trending Discussions
Learning
json-server | |
fastapi | 0.75.2 |
beego | Release v2.0.2 |
yapi | 修复 沙箱 提权问题 |
NeteaseCloudMusicApi | v4.5.12 |
json-server |
fastapi 0.75.2 |
beego Release v2.0.2 |
yapi 修复 沙箱 提权问题 |
NeteaseCloudMusicApi v4.5.12 |
by public-apis python
184682 MIT
A collective list of free APIs
by typicode javascript
59172 MIT
Get a full fake REST API with zero coding in less than 30 seconds (seriously)
by iptv-org javascript
49563 Unlicense
Collection of publicly available IPTV channels from all over the world
by tiangolo python
44054 MIT
FastAPI framework, high performance, easy to learn, fast to code, ready for production
by beego go
28039 NOASSERTION
beego is an open-source, high-performance web framework for the Go programming language.
by request javascript
25202 Apache-2.0
🏊🏾 Simplified HTTP request client.
by YMFE javascript
23924 Apache-2.0
YApi 是一个可本地部署的、打通前后端及QA的、可视化的接口管理平台
by Binaryify javascript
23544 MIT
网易云音乐 Node.js API service
by encode python
22954 NOASSERTION
Web APIs for Django. 🎸
by public-apis python
184682 MIT
A collective list of free APIs
by typicode javascript
59172 MIT
Get a full fake REST API with zero coding in less than 30 seconds (seriously)
by iptv-org javascript
49563 Unlicense
Collection of publicly available IPTV channels from all over the world
by tiangolo python
44054 MIT
FastAPI framework, high performance, easy to learn, fast to code, ready for production
by beego go
28039 NOASSERTION
beego is an open-source, high-performance web framework for the Go programming language.
by request javascript
25202 Apache-2.0
🏊🏾 Simplified HTTP request client.
by YMFE javascript
23924 Apache-2.0
YApi 是一个可本地部署的、打通前后端及QA的、可视化的接口管理平台
by Binaryify javascript
23544 MIT
网易云音乐 Node.js API service
by encode python
22954 NOASSERTION
Web APIs for Django. 🎸
by amplication typescript
7019 Apache-2.0
Amplication is an open‑source development tool. It helps you develop quality Node.js applications without spending time on repetitive coding tasks.
by trpc typescript
5188 MIT
🧙♀️ End-to-end typesafe APIs made easy
by BrasilAPI javascript
4411 MIT
Vamos transformar o Brasil em uma API?
by pestphp php
4192 MIT
Pest is an amazing and elegant PHP Testing Framework with a focus on simplicity
by Mrs4s go
4085 AGPL-3.0
cqhttp的golang实现,轻量、原生跨平台.
by public-api-lists python
3318 MIT
A collective list of free APIs for use in software and web development 🚀 (Clone of https://github.com/public-apis/public-apis)
by ducaale rust
2772 MIT
Friendly and fast tool for sending HTTP requests
by vitalik python
2769 MIT
💨 Fast, Async-ready, Openapi, type hints based framework for building APIs
by encoredev go
2669 MPL-2.0
Encore is the Go Backend Development Engine helping developers escape the maze of complexity.
by amplication typescript
7019 Apache-2.0
Amplication is an open‑source development tool. It helps you develop quality Node.js applications without spending time on repetitive coding tasks.
by trpc typescript
5188 MIT
🧙♀️ End-to-end typesafe APIs made easy
by BrasilAPI javascript
4411 MIT
Vamos transformar o Brasil em uma API?
by pestphp php
4192 MIT
Pest is an amazing and elegant PHP Testing Framework with a focus on simplicity
by Mrs4s go
4085 AGPL-3.0
cqhttp的golang实现,轻量、原生跨平台.
by public-api-lists python
3318 MIT
A collective list of free APIs for use in software and web development 🚀 (Clone of https://github.com/public-apis/public-apis)
by ducaale rust
2772 MIT
Friendly and fast tool for sending HTTP requests
by vitalik python
2769 MIT
💨 Fast, Async-ready, Openapi, type hints based framework for building APIs
by encoredev go
2669 MPL-2.0
Encore is the Go Backend Development Engine helping developers escape the maze of complexity.
1
66 Libraries
5638
2
65 Libraries
36172
3
51 Libraries
5355
4
50 Libraries
482
5
42 Libraries
2749
6
37 Libraries
4002
7
36 Libraries
17415
8
34 Libraries
1688
9
30 Libraries
190
10
28 Libraries
6785
Fetching JSON array data from an API using React can be used in various contexts where you need to retrieve and display data from an external API in a React application. Some examples might include the following: You can use the fetch function, a built-in function for making HTTP queries, or a library like Axios to complete the request to fetch data from a JSON array from an API in a React application. This pre-written code snippet will show you how to fetch data from a JSON file easily and consume it in your React project. Steps- Here's an example of how you might implement this: Fig 1: Preview of the output that you will get on running this code from your IDE. In this solution we're using React and Axios library. Follow the steps carefully to get the output easily. You can also refer this url 'DEMO' for getting the above output. I hope you found this useful. I have added the link to dependent libraries, version information in the following sections. I found this code snippet by searching for 'display data from jsonplaceholder api using react'in kandi. You can try any such use case! I tested this solution in the following versions. Be mindful of changes when working with other versions. Using this solution, we are able to fetch Json array data from API using React with simple steps. This process also facilities an easy way to use, hassle-free method to create a hands-on working version of code which would help us to fetch Json array data from API using React. You can also search for any libraries on kandi like 'react' and 'axios'.
Code
Instructions
Environment Tested
Dependent Library
Support
Java API gateway is software that accepts an app's user request, diverts it to other backend services, gathers the necessary info, and supplies it to the application user in a single, combined package. It also provides analytics, threat protection layers, and other application security. Java API gateway is a common entry point for all API calls that come into an app, whether hosted on-premises or in the cloud. It receives remote requests and returns the requested data. Consider the web application of a restaurant. Even though all that information is gathered and delivered from various backend microservices or APIs, a user can enter a single request and easily access the: An API gateway receives and processes their request. Developers use microservices in DevOps organizations to build and deploy apps in a fast-paced, iterative manner. API gateways provide three key services between a user and a collection of microservices: request routing, API composition, and protocol translation. In addition to simply servicing requests, an API gateway adds value by making data available in a format appropriate for the requestor's technology. For example, someone using a web browser to request information about a retail store receives far more information than someone using a mobile phone to request and view the same store's data. APIs are one of the most standard ways for microservices to communicate with one another. As integration and interconnectivity gain importance, APIs are becoming more and more crucial daily for software developers. Furthermore, APIs are used to provision infrastructure in modern cloud development, including the serverless model, and can use Java API gateway to deploy and manage serverless functions. Several Java API libraries help engineers to reuse code for networking other functionalities of the applications. Some examples of standard libraries are- scalecube-services, service-proxy, kong-java-client, aws-gateway-executor, gateleen, handyman, API-gateway, product-microgateway, shenyu, ship-gate, among others. Check out the below list to find the best top 10 Java API gateway libraries for your application development:
Synarion IT Solutions is a FIFS Certified Fantasy Sports App Development Company in India. We have developed 50+ fantasy sports applications. https://www.synarionit.com/fantasy-sports-development.html
Fetching JSON array data from an API using React can be used in various contexts where you need to retrieve and display data from an external API in a React application. Some examples might include the following: You can use the fetch function, a built-in function for making HTTP queries, or a library like Axios to complete the request to fetch data from a JSON array from an API in a React application. This pre-written code snippet will show you how to fetch data from a JSON file easily and consume it in your React project. Steps- Here's an example of how you might implement this: Fig 1: Preview of the output that you will get on running this code from your IDE. In this solution we're using React and Axios library. Follow the steps carefully to get the output easily. You can also refer this url 'DEMO' for getting the above output. I hope you found this useful. I have added the link to dependent libraries, version information in the following sections. I found this code snippet by searching for 'display data from jsonplaceholder api using react'in kandi. You can try any such use case! I tested this solution in the following versions. Be mindful of changes when working with other versions. Using this solution, we are able to fetch Json array data from API using React with simple steps. This process also facilities an easy way to use, hassle-free method to create a hands-on working version of code which would help us to fetch Json array data from API using React. You can also search for any libraries on kandi like 'react' and 'axios'.
Code
Instructions
Environment Tested
Dependent Library
Support
Java API gateway is software that accepts an app's user request, diverts it to other backend services, gathers the necessary info, and supplies it to the application user in a single, combined package. It also provides analytics, threat protection layers, and other application security. Java API gateway is a common entry point for all API calls that come into an app, whether hosted on-premises or in the cloud. It receives remote requests and returns the requested data. Consider the web application of a restaurant. Even though all that information is gathered and delivered from various backend microservices or APIs, a user can enter a single request and easily access the: An API gateway receives and processes their request. Developers use microservices in DevOps organizations to build and deploy apps in a fast-paced, iterative manner. API gateways provide three key services between a user and a collection of microservices: request routing, API composition, and protocol translation. In addition to simply servicing requests, an API gateway adds value by making data available in a format appropriate for the requestor's technology. For example, someone using a web browser to request information about a retail store receives far more information than someone using a mobile phone to request and view the same store's data. APIs are one of the most standard ways for microservices to communicate with one another. As integration and interconnectivity gain importance, APIs are becoming more and more crucial daily for software developers. Furthermore, APIs are used to provision infrastructure in modern cloud development, including the serverless model, and can use Java API gateway to deploy and manage serverless functions. Several Java API libraries help engineers to reuse code for networking other functionalities of the applications. Some examples of standard libraries are- scalecube-services, service-proxy, kong-java-client, aws-gateway-executor, gateleen, handyman, API-gateway, product-microgateway, shenyu, ship-gate, among others. Check out the below list to find the best top 10 Java API gateway libraries for your application development:
Synarion IT Solutions is a FIFS Certified Fantasy Sports App Development Company in India. We have developed 50+ fantasy sports applications. https://www.synarionit.com/fantasy-sports-development.html
QUESTION
How to redirect in React Router v6?
Asked 2022-Mar-24 at 17:22I am trying to upgrade to React Router v6 (react-router-dom 6.0.1
).
Here is my updated code:
1import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
2
3<BrowserRouter>
4 <Routes>
5 <Route path="/" element={<Home />} />
6 <Route path="/lab" element={<Lab />} />
7 <Route render={() => <Navigate to="/" />} />
8 </Routes>
9</BrowserRouter>
10
The last Route
is redirecting the rest of paths to /
.
However, I got an error
TS2322: Type '{ render: () => Element; }' is not assignable to type 'IntrinsicAttributes & (PathRouteProps | LayoutRouteProps | IndexRouteProps)'. Property 'render' does not exist on type 'IntrinsicAttributes & (PathRouteProps | LayoutRouteProps | IndexRouteProps)'.
However, based on the doc, it does have render
for Route
. How to use it correctly?
ANSWER
Answered 2022-Mar-18 at 18:41I think you should use the no match route approach.
Check this in the documentation.
https://reactrouter.com/docs/en/v6/getting-started/tutorial#adding-a-no-match-route
1import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
2
3<BrowserRouter>
4 <Routes>
5 <Route path="/" element={<Home />} />
6 <Route path="/lab" element={<Lab />} />
7 <Route render={() => <Navigate to="/" />} />
8 </Routes>
9</BrowserRouter>
10import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
11
12<BrowserRouter>
13 <Routes>
14 <Route path="/" element={<Home />} />
15 <Route path="/lab" element={<Lab />} />
16 <Route
17 path="*"
18 element={<Navigate to="/" replace />}
19 />
20 </Routes>
21</BrowserRouter>
22
To keep the history clean, you should set replace
prop. This will avoid extra redirects after the user click back. Thanks @Paul for this tip.
QUESTION
Is every "complete" object a "most-derived" object?
Asked 2022-Mar-21 at 02:30Per [intro.object]/2:
[..] An object that is not a subobject of any other object is called a complete object [..].
So consider this snippet of code:
1struct Base {};
2struct Derived : Base {};
3struct MostDerived : Derived {};
4
I can't understand the wording in this quote from the standard:
If a complete object, a member subobject, or an array element is of class type, its type is considered the most derived class [..] An object of a most derived class type or of a non-class type is called a most derived object.
From the quote what I understand is that a type of a complete object is of "most-derived" class type. I stopped here, I really do not understand the rest of the wording.
Per the question "What does the "most derived object" mean?" I think that (correct me if I am wrong), objects of type "most-derived" class only, like MostDerived
, are called "most-derived" objects. Is this true?
If I have created an object of Base
like this: Base b_obj = Base()
, is the object b_obj
a "most-derived" object?
If I have created an object of Derived
like this: Derived d_obj = Derived()
, is the object d_obj
also a "most-derived" object?
Does the word "derived" in "most-derived" mean that the object is an object of a class like MostDerived
, or mean that the object has no class subobject in it?
ANSWER
Answered 2022-Mar-21 at 00:321struct Base {};
2struct Derived : Base {};
3struct MostDerived : Derived {};
4void foo() {
5 int i = 0; // complete object, but not most-derived (not class type)
6}
7
8class A {
9 int i = 0; // non complete object, not most-derived
10}
11
12void bar() {
13 A a; // complete object, but not derived, so can't be "most derived"
14}
15
16class B : A { }
17
18void biz() {
19 B b; // complete object, derived object, and most-derived object
20}
21
Is every "complete" object is "most-derived" object
No. A most-derived object is an object of a most-derived class, and a most-derived class must be of a class type. Objects may be of class type, but non-class type objects also exist.
So if I have created an object of Base like this:
Base b_obj = Base()
, Is the objectb_obj
is "most-derived" object?
Yes. The most-derived object of b_obj
is an object of type Base
. This is not necessarily a complete object, however, since this could be a class member definition. Again, complete is not synonymous with most-derived.
Also if I have created an object of Derived like this:
Derived d_obj = Derived()
, Is the objectd_obj
is also a "most-derived" object?
Yes. The most-derived object of d_obj
is an object of type Derived
.
If you have an object created as type MostDerived
:
1struct Base {};
2struct Derived : Base {};
3struct MostDerived : Derived {};
4void foo() {
5 int i = 0; // complete object, but not most-derived (not class type)
6}
7
8class A {
9 int i = 0; // non complete object, not most-derived
10}
11
12void bar() {
13 A a; // complete object, but not derived, so can't be "most derived"
14}
15
16class B : A { }
17
18void biz() {
19 B b; // complete object, derived object, and most-derived object
20}
21MostDerived md;
22
MostDerived
Derived
Base
MostDerived
Derived
, which is neither a complete object nor a most-derived objectDerived
has a subobject of type Base
, which is neither a complete object nor a most-derived object.QUESTION
Filter out everything before a condition is met, keep all elements after
Asked 2022-Feb-23 at 21:32I was wondering if there was an easy solution to the the following problem. The problem here is that I want to keep every element occurring inside this list after the initial condition is true. The condition here being that I want to remove everything before the condition that a value is greater than 18 is true, but keep everything after. Example
Input:
1p = [4,9,10,4,20,13,29,3,39]
2
Expected output:
1p = [4,9,10,4,20,13,29,3,39]
2p = [20,13,29,3,39]
3
I know that you can filter over the entire list through
1p = [4,9,10,4,20,13,29,3,39]
2p = [20,13,29,3,39]
3[x for x in p if x>18]
4
But I want to stop this operation once the first value above 18 is found, and then include the rest of the values regardless if they satisfy the condition or not. It seems like an easy problem but I haven't found the solution to it yet.
ANSWER
Answered 2022-Feb-05 at 19:59You can use itertools.dropwhile
:
1p = [4,9,10,4,20,13,29,3,39]
2p = [20,13,29,3,39]
3[x for x in p if x>18]
4from itertools import dropwhile
5
6p = [4,9,10,4,20,13,29,3,39]
7
8p = dropwhile(lambda x: x <= 18, p)
9print(*p) # 20 13 29 3 39
10
In my opinion, this is arguably the easiest-to-read version. This also corresponds to a common pattern in other functional programming languages, such as dropWhile (<=18) p
in Haskell and p.dropWhile(_ <= 18)
in Scala.
Alternatively, using walrus operator (only available in python 3.8+):
1p = [4,9,10,4,20,13,29,3,39]
2p = [20,13,29,3,39]
3[x for x in p if x>18]
4from itertools import dropwhile
5
6p = [4,9,10,4,20,13,29,3,39]
7
8p = dropwhile(lambda x: x <= 18, p)
9print(*p) # 20 13 29 3 39
10exceeded = False
11p = [x for x in p if (exceeded := exceeded or x > 18)]
12print(p) # [20, 13, 29, 3, 39]
13
But my guess is that some people don't like this style. In that case, one can do an explicit for
loop (ilkkachu's suggestion):
1p = [4,9,10,4,20,13,29,3,39]
2p = [20,13,29,3,39]
3[x for x in p if x>18]
4from itertools import dropwhile
5
6p = [4,9,10,4,20,13,29,3,39]
7
8p = dropwhile(lambda x: x <= 18, p)
9print(*p) # 20 13 29 3 39
10exceeded = False
11p = [x for x in p if (exceeded := exceeded or x > 18)]
12print(p) # [20, 13, 29, 3, 39]
13for i, x in enumerate(p):
14 if x > 18:
15 output = p[i:]
16 break
17else:
18 output = [] # alternatively just put output = [] before for
19
QUESTION
"Configuring the trigger failed, edit and save the pipeline again" with no noticeable error and no further details
Asked 2022-Feb-16 at 10:33I have run in to an odd problem after converting a bunch of my YAML pipelines to use templates for holding job logic as well as for defining my pipeline variables. The pipelines run perfectly fine, however I get a "Some recent issues detected related to pipeline trigger." warning at the top of the pipeline summary page and viewing details only states: "Configuring the trigger failed, edit and save the pipeline again."
The odd part here is that the pipeline works completely fine, including triggers. Nothing is broken and no further details are given about the supposed issue. I currently have YAML triggers overridden for the pipeline, but I did also define the same trigger in the YAML to see if that would help (it did not).
I'm looking for any ideas on what might be causing this or how I might be able to further troubleshoot it given the complete lack of detail that the error/warning provides. It's causing a lot of confusion among developers who think there might be a problem with their builds as a result of the warning.
Here is the main pipeline. the build repository is a shared repository for holding code that is used across multiple repos in the build system. dev.yaml contains dev environment specific variable values. Shared holds conditionally set variables based on the branch the pipeline is running on.
1name: ProductName_$(BranchNameLower)_dev_$(MajorVersion)_$(MinorVersion)_$(BuildVersion)_$(Build.BuildId)
2resources:
3 repositories:
4 - repository: self
5 - repository: build
6 type: git
7 name: Build
8 ref: master
9
10# This trigger isn't used yet, but we want it defined for later.
11trigger:
12 batch: true
13 branches:
14 include:
15 - 'dev'
16
17variables:
18- template: YAML/variables/shared.yaml@build
19- template: YAML/variables/dev.yaml@build
20
21jobs:
22- template: ProductNameDevJob.yaml
23 parameters:
24 pipelinePool: ${{ variables.PipelinePool }}
25 validRef: ${{ variables.ValidRef }}
26
Then this is the start of the actual job yaml. It provides a reusable definition of the job that can be used in more than one over-arching pipeline:
1name: ProductName_$(BranchNameLower)_dev_$(MajorVersion)_$(MinorVersion)_$(BuildVersion)_$(Build.BuildId)
2resources:
3 repositories:
4 - repository: self
5 - repository: build
6 type: git
7 name: Build
8 ref: master
9
10# This trigger isn't used yet, but we want it defined for later.
11trigger:
12 batch: true
13 branches:
14 include:
15 - 'dev'
16
17variables:
18- template: YAML/variables/shared.yaml@build
19- template: YAML/variables/dev.yaml@build
20
21jobs:
22- template: ProductNameDevJob.yaml
23 parameters:
24 pipelinePool: ${{ variables.PipelinePool }}
25 validRef: ${{ variables.ValidRef }}
26parameters:
27- name: dependsOn
28 type: object
29 default: {}
30- name: pipelinePool
31 default: ''
32- name: validRef
33 default: ''
34- name: noCI
35 type: boolean
36 default: false
37- name: updateBeforeRun
38 type: boolean
39 default: false
40
41jobs:
42- job: Build_ProductName
43 displayName: 'Build ProductName'
44 pool:
45 name: ${{ parameters.pipelinePool }}
46 demands:
47 - msbuild
48 - visualstudio
49 dependsOn:
50 - ${{ each dependsOnThis in parameters.dependsOn }}:
51 - ${{ dependsOnThis }}
52 condition: and(succeeded(), eq(variables['Build.SourceBranch'], variables['ValidRef']))
53
54 steps:
55**step logic here
56
Finally, we have the variable YAML which conditionally sets pipeline variables based on what we are building:
1name: ProductName_$(BranchNameLower)_dev_$(MajorVersion)_$(MinorVersion)_$(BuildVersion)_$(Build.BuildId)
2resources:
3 repositories:
4 - repository: self
5 - repository: build
6 type: git
7 name: Build
8 ref: master
9
10# This trigger isn't used yet, but we want it defined for later.
11trigger:
12 batch: true
13 branches:
14 include:
15 - 'dev'
16
17variables:
18- template: YAML/variables/shared.yaml@build
19- template: YAML/variables/dev.yaml@build
20
21jobs:
22- template: ProductNameDevJob.yaml
23 parameters:
24 pipelinePool: ${{ variables.PipelinePool }}
25 validRef: ${{ variables.ValidRef }}
26parameters:
27- name: dependsOn
28 type: object
29 default: {}
30- name: pipelinePool
31 default: ''
32- name: validRef
33 default: ''
34- name: noCI
35 type: boolean
36 default: false
37- name: updateBeforeRun
38 type: boolean
39 default: false
40
41jobs:
42- job: Build_ProductName
43 displayName: 'Build ProductName'
44 pool:
45 name: ${{ parameters.pipelinePool }}
46 demands:
47 - msbuild
48 - visualstudio
49 dependsOn:
50 - ${{ each dependsOnThis in parameters.dependsOn }}:
51 - ${{ dependsOnThis }}
52 condition: and(succeeded(), eq(variables['Build.SourceBranch'], variables['ValidRef']))
53
54 steps:
55**step logic here
56variables:
57- ${{ if or(eq(variables['Build.SourceBranch'], 'refs/heads/dev'), eq(variables['Build.SourceBranch'], 'refs/heads/users/ahenderson/azure_devops_build')) }}:
58 - name: BranchName
59 value: Dev
60** Continue with rest of pipeline variables and settings of each value for each different context.
61
ANSWER
Answered 2021-Aug-17 at 14:58I think I may have figured out the problem. It appears that this is related to the use of conditionals in the variable setup. While the variables will be set in any valid trigger configuration, it appears that the proper values are not used during validation and that may have been causing the problem. Switching my conditional variables to first set a default value and then replace the value conditionally seems to have fixed the problem.
It would be nice if Microsoft would give a more useful error message here, something to the extent of the values not being found for a given variable, but adding defaults does seem to have fixed the problem.
QUESTION
Multiple labels per item on Kendo chart
Asked 2022-Jan-02 at 21:14I'm trying to get multiple label per item on Kendo Column chart
Desired layout looks like this
I was able to get only this layout
1import { Component } from '@angular/core';
2import { groupBy, GroupResult } from '@progress/kendo-data-query';
3import { ValueAxisLabels } from '@progress/kendo-angular-charts';
4
5export type TrendItem = {
6 clientName: string;
7 periodName: string;
8 income: number;
9};
10
11@Component({
12 selector: 'my-app',
13 template: `
14 <kendo-chart>
15 <kendo-chart-category-axis>
16 <kendo-chart-category-axis-item [categories]="categories">
17 </kendo-chart-category-axis-item>
18 </kendo-chart-category-axis>
19
20 <kendo-chart-value-axis>
21 <kendo-chart-value-axis-item [labels]="valueAxisLabels">
22 </kendo-chart-value-axis-item>
23 </kendo-chart-value-axis>
24
25 <kendo-chart-series>
26 <kendo-chart-series-item *ngFor="let groupedResult of groupedTrendsByPeriod" [data]="groupedResult.items" field="income" type="column">
27 <kendo-chart-series-item-labels [content]="labelVisual">
28 </kendo-chart-series-item-labels>
29 </kendo-chart-series-item>
30 </kendo-chart-series>
31 </kendo-chart>
32 `,
33})
34export class AppComponent {
35 public valueAxisLabels: ValueAxisLabels = {
36 font: 'bold 16px Arial, sans-serif',
37 };
38
39 public trendItems: TrendItem[] = [
40 {
41 clientName: 'Client1',
42 periodName: 'Q1 2020',
43 income: 20,
44 },
45 {
46 clientName: 'Client1',
47 periodName: 'Q2 2020',
48 income: 15,
49 },
50 {
51 clientName: 'Client1',
52 periodName: 'Q3 2020',
53 income: 35,
54 },
55 {
56 clientName: 'Client1',
57 periodName: 'Q4 2020',
58 income: 40,
59 },
60 {
61 clientName: 'Client2',
62 periodName: 'Q1 2020',
63 income: 15,
64 },
65 {
66 clientName: 'Client2',
67 periodName: 'Q2 2020',
68 income: 20,
69 },
70 {
71 clientName: 'Client2',
72 periodName: 'Q3 2020',
73 income: 15,
74 },
75 {
76 clientName: 'Client2',
77 periodName: 'Q4 2020',
78 income: 30,
79 }
80 ];
81
82 public categories = (groupBy(this.trendItems, [{ field: 'clientName' }]) as GroupResult[])
83 .map((e) => e.value);
84
85 public groupedTrendsByPeriod = groupBy(this.trendItems, [{ field: 'periodName' }]) as GroupResult[];
86
87 public labelVisual(e: { dataItem: TrendItem }) {
88 return `$${e.dataItem.income}\r\n${e.dataItem.periodName}`;
89 }
90}
91
You can try this code here.
My current result look like this
So my question is how to display multiple labels per item like on the first picture?
My current obstacles.
<kendo-chart-series-item-labels>
elements. Only one will be rendered, rest will be ignored.ANSWER
Answered 2022-Jan-02 at 08:18QUESTION
Python 3.10 pattern matching (PEP 634) - wildcard in string
Asked 2021-Dec-17 at 10:43I got a large list of JSON objects that I want to parse depending on the start of one of the keys, and just wildcard the rest. A lot of the keys are similar, like "matchme-foo"
and "matchme-bar"
. There is a builtin wildcard, but it is only used for whole values, kinda like an else
.
I might be overlooking something but I can't find a solution anywhere in the proposal:
https://docs.python.org/3/whatsnew/3.10.html#pep-634-structural-pattern-matching
Also a bit more about it in PEP-636:
https://www.python.org/dev/peps/pep-0636/#going-to-the-cloud-mappings
My data looks like this:
1data = [{
2 "id" : "matchme-foo",
3 "message": "hallo this is a message",
4 },{
5 "id" : "matchme-bar",
6 "message": "goodbye",
7 },{
8 "id" : "anotherid",
9 "message": "completely diffrent event"
10 }, ...]
11
I want to do something that can match the id without having to make a long list of |
's.
Something like this:
1data = [{
2 "id" : "matchme-foo",
3 "message": "hallo this is a message",
4 },{
5 "id" : "matchme-bar",
6 "message": "goodbye",
7 },{
8 "id" : "anotherid",
9 "message": "completely diffrent event"
10 }, ...]
11for event in data:
12 match event:
13 case {'id':'matchme-*'}: # Match all 'matchme-' no matter what comes next
14 log.INFO(event['message'])
15 case {'id':'anotherid'}:
16 log.ERROR(event['message'])
17
It's a relatively new addition to Python so there aren't many guides on how to use it yet.
ANSWER
Answered 2021-Dec-17 at 10:43You can use a guard:
1data = [{
2 "id" : "matchme-foo",
3 "message": "hallo this is a message",
4 },{
5 "id" : "matchme-bar",
6 "message": "goodbye",
7 },{
8 "id" : "anotherid",
9 "message": "completely diffrent event"
10 }, ...]
11for event in data:
12 match event:
13 case {'id':'matchme-*'}: # Match all 'matchme-' no matter what comes next
14 log.INFO(event['message'])
15 case {'id':'anotherid'}:
16 log.ERROR(event['message'])
17for event in data:
18 match event:
19 case {'id': x} if x.startswith("matchme"): # guard
20 print(event["message"])
21 case {'id':'anotherid'}:
22 print(event["message"])
23
Quoting from the official documentation,
Guard
We can add an
if
clause to a pattern, known as a “guard”. If the guard isfalse
, match goes on to try the nextcase
block. Note that value capture happens before the guard is evaluated:
1data = [{
2 "id" : "matchme-foo",
3 "message": "hallo this is a message",
4 },{
5 "id" : "matchme-bar",
6 "message": "goodbye",
7 },{
8 "id" : "anotherid",
9 "message": "completely diffrent event"
10 }, ...]
11for event in data:
12 match event:
13 case {'id':'matchme-*'}: # Match all 'matchme-' no matter what comes next
14 log.INFO(event['message'])
15 case {'id':'anotherid'}:
16 log.ERROR(event['message'])
17for event in data:
18 match event:
19 case {'id': x} if x.startswith("matchme"): # guard
20 print(event["message"])
21 case {'id':'anotherid'}:
22 print(event["message"])
23match point:
24 case Point(x, y) if x == y:
25 print(f"The point is located on the diagonal Y=X at {x}.")
26 case Point(x, y):
27 print(f"Point is not on the diagonal.")
28
QUESTION
Redirect in react-router-dom V6
Asked 2021-Dec-15 at 05:41I need to navigate back to the original requested URL after login.
For example, user enters www.example.com/settings
as user is not authenticated, it will navigate to login page www.example.com/login
.
Once authenticated, it should navigate back to www.example.com/settings
automatically.
My original approach with react-router-dom
v5 is quite simple:
1const PrivateRoute = ({ isLoggedIn, component: Component, ...rest }) => {
2 return (
3 <Route
4 {...rest}
5 render={(props) =>
6 isLoggedIn? (
7 <Component {...props} />
8 ) : (
9 <Redirect
10 to={{ pathname: `/login/${props.location.search}`, state: { from: props.location } }}
11 />
12 )
13 }
14 />
15 );
16};
17
18
19<PrivateRoute exact isLoggedIn={isLoggedIn} path="/settings" component={Settings} />
20
21
Can some one tell me how to do that in v6? Thanks in advance
ANSWER
Answered 2021-Dec-15 at 05:41In react-router-dom
v6 rendering routes and handling redirects is quite different than in v5. Gone are custom route components, they are replaced with a wrapper component pattern.
v5 - Custom Route
Takes props and conditionally renders a Route
component with the route props passed through or a Redirect
component with route state holding the current location
.
1const PrivateRoute = ({ isLoggedIn, component: Component, ...rest }) => {
2 return (
3 <Route
4 {...rest}
5 render={(props) =>
6 isLoggedIn? (
7 <Component {...props} />
8 ) : (
9 <Redirect
10 to={{ pathname: `/login/${props.location.search}`, state: { from: props.location } }}
11 />
12 )
13 }
14 />
15 );
16};
17
18
19<PrivateRoute exact isLoggedIn={isLoggedIn} path="/settings" component={Settings} />
20
21const CustomRoute = ({ isLoggedIn, ...props }) => {
22 const location = useLocation();
23 return isLoggedIn? (
24 <Route {...props} />
25 ) : (
26 <Redirect
27 to={{
28 pathname: `/login/${location.search}`,
29 state: { location },
30 }}
31 />
32 );
33};
34
...
1const PrivateRoute = ({ isLoggedIn, component: Component, ...rest }) => {
2 return (
3 <Route
4 {...rest}
5 render={(props) =>
6 isLoggedIn? (
7 <Component {...props} />
8 ) : (
9 <Redirect
10 to={{ pathname: `/login/${props.location.search}`, state: { from: props.location } }}
11 />
12 )
13 }
14 />
15 );
16};
17
18
19<PrivateRoute exact isLoggedIn={isLoggedIn} path="/settings" component={Settings} />
20
21const CustomRoute = ({ isLoggedIn, ...props }) => {
22 const location = useLocation();
23 return isLoggedIn? (
24 <Route {...props} />
25 ) : (
26 <Redirect
27 to={{
28 pathname: `/login/${location.search}`,
29 state: { location },
30 }}
31 />
32 );
33};
34<PrivateRoute
35 exact
36 isLoggedIn={isLoggedIn}
37 path="/settings"
38 component={Settings}
39/>
40
v6 - Custom Wrapper
Takes props and conditionally renders an Outlet
component for nested Route
components to be rendered into or a Navigate
component with route state holding the current location
.
1const PrivateRoute = ({ isLoggedIn, component: Component, ...rest }) => {
2 return (
3 <Route
4 {...rest}
5 render={(props) =>
6 isLoggedIn? (
7 <Component {...props} />
8 ) : (
9 <Redirect
10 to={{ pathname: `/login/${props.location.search}`, state: { from: props.location } }}
11 />
12 )
13 }
14 />
15 );
16};
17
18
19<PrivateRoute exact isLoggedIn={isLoggedIn} path="/settings" component={Settings} />
20
21const CustomRoute = ({ isLoggedIn, ...props }) => {
22 const location = useLocation();
23 return isLoggedIn? (
24 <Route {...props} />
25 ) : (
26 <Redirect
27 to={{
28 pathname: `/login/${location.search}`,
29 state: { location },
30 }}
31 />
32 );
33};
34<PrivateRoute
35 exact
36 isLoggedIn={isLoggedIn}
37 path="/settings"
38 component={Settings}
39/>
40const CustomWrapper = ({ isLoggedIn, ...props }) => {
41 const location = useLocation();
42 return isLoggedIn? (
43 <Outlet />
44 ) : (
45 <Navigate
46 to={`/login/${location.search}`}
47 replace
48 state={{ location }}
49 />
50 )
51};
52
...
1const PrivateRoute = ({ isLoggedIn, component: Component, ...rest }) => {
2 return (
3 <Route
4 {...rest}
5 render={(props) =>
6 isLoggedIn? (
7 <Component {...props} />
8 ) : (
9 <Redirect
10 to={{ pathname: `/login/${props.location.search}`, state: { from: props.location } }}
11 />
12 )
13 }
14 />
15 );
16};
17
18
19<PrivateRoute exact isLoggedIn={isLoggedIn} path="/settings" component={Settings} />
20
21const CustomRoute = ({ isLoggedIn, ...props }) => {
22 const location = useLocation();
23 return isLoggedIn? (
24 <Route {...props} />
25 ) : (
26 <Redirect
27 to={{
28 pathname: `/login/${location.search}`,
29 state: { location },
30 }}
31 />
32 );
33};
34<PrivateRoute
35 exact
36 isLoggedIn={isLoggedIn}
37 path="/settings"
38 component={Settings}
39/>
40const CustomWrapper = ({ isLoggedIn, ...props }) => {
41 const location = useLocation();
42 return isLoggedIn? (
43 <Outlet />
44 ) : (
45 <Navigate
46 to={`/login/${location.search}`}
47 replace
48 state={{ location }}
49 />
50 )
51};
52<Route path="settings" element={<CustomWrapper isLoggedIn={isLoggedIn} />} >
53 <Route path="settings" element={<Settings />} />
54</Route>
55
QUESTION
Patch request not patching - 403 returned - django rest framework
Asked 2021-Dec-11 at 07:34I'm trying to test an API endpoint with a patch request to ensure it works.
I'm using APILiveServerTestCase
but can't seem to get the permissions required to patch the item. I created one user (adminuser
) who is a superadmin with access to everything and all permissions.
My test case looks like this:
1class FutureVehicleURLTest(APILiveServerTestCase):
2 def setUp(self):
3 # Setup users and some vehicle data we can query against
4 management.call_command("create_users_and_vehicle_data", verbosity=0)
5 self.user = UserFactory()
6 self.admin_user = User.objects.get(username="adminuser")
7 self.future_vehicle = f.FutureVehicleFactory(
8 user=self.user,
9 last_updated_by=self.user,
10 )
11 self.vehicle = f.VehicleFactory(
12 user=self.user,
13 created_by=self.user,
14 modified_by=self.user,
15 )
16 self.url = reverse("FutureVehicles-list")
17 self.full_url = self.live_server_url + self.url
18 time = str(datetime.now())
19 self.form_data = {
20 "signature": "TT",
21 "purchasing": True,
22 "confirmed_at": time,
23 }
24
I've tried this test a number of different ways - all giving the same result (403).
I have setup the python debugger in the test, and I have tried actually going to http://localhost:xxxxx/admin/
in the browser and logging in manually with any user but the page just refreshes when I click to login and I never get 'logged in' to see the admin. I'm not sure if that's because it doesn't completely work from within a debugger like that or not.
My test looks like this (using the Requests library):
1class FutureVehicleURLTest(APILiveServerTestCase):
2 def setUp(self):
3 # Setup users and some vehicle data we can query against
4 management.call_command("create_users_and_vehicle_data", verbosity=0)
5 self.user = UserFactory()
6 self.admin_user = User.objects.get(username="adminuser")
7 self.future_vehicle = f.FutureVehicleFactory(
8 user=self.user,
9 last_updated_by=self.user,
10 )
11 self.vehicle = f.VehicleFactory(
12 user=self.user,
13 created_by=self.user,
14 modified_by=self.user,
15 )
16 self.url = reverse("FutureVehicles-list")
17 self.full_url = self.live_server_url + self.url
18 time = str(datetime.now())
19 self.form_data = {
20 "signature": "TT",
21 "purchasing": True,
22 "confirmed_at": time,
23 }
24 def test_patch_request_updates_object(self):
25 data_dict = {
26 "signature": "TT",
27 "purchasing": "true",
28 "confirmed_at": datetime.now().strftime("%m/%d/%Y, %H:%M:%S"),
29 }
30 url = self.full_url + str(self.future_vehicle.id) + "/"
31 client = requests.Session()
32 client.auth = HTTPBasicAuth(self.admin_user.username, "test")
33 client.headers.update({"x-test": "true"})
34 response = client.get(self.live_server_url + "/admin/")
35 csrftoken = response.cookies["csrftoken"]
36 # interact with the api
37 response = client.patch(
38 url,
39 data=json.dumps(data_dict),
40 cookies=response.cookies,
41 headers={
42 "X-Requested-With": "XMLHttpRequest",
43 "X-CSRFTOKEN": csrftoken,
44 },
45 )
46 # RESPONSE GIVES 403 PERMISSION DENIED
47 fte_future_vehicle = FutureVehicle.objects.filter(
48 id=self.future_vehicle.id
49 ).first()
50 # THIS ERRORS WITH '' not equal to 'TT'
51 self.assertEqual(fte_future_vehicle.signature, "TT")
52
I have tried it very similarly to the documentation using APIRequestFactory
and forcing authentication:
1class FutureVehicleURLTest(APILiveServerTestCase):
2 def setUp(self):
3 # Setup users and some vehicle data we can query against
4 management.call_command("create_users_and_vehicle_data", verbosity=0)
5 self.user = UserFactory()
6 self.admin_user = User.objects.get(username="adminuser")
7 self.future_vehicle = f.FutureVehicleFactory(
8 user=self.user,
9 last_updated_by=self.user,
10 )
11 self.vehicle = f.VehicleFactory(
12 user=self.user,
13 created_by=self.user,
14 modified_by=self.user,
15 )
16 self.url = reverse("FutureVehicles-list")
17 self.full_url = self.live_server_url + self.url
18 time = str(datetime.now())
19 self.form_data = {
20 "signature": "TT",
21 "purchasing": True,
22 "confirmed_at": time,
23 }
24 def test_patch_request_updates_object(self):
25 data_dict = {
26 "signature": "TT",
27 "purchasing": "true",
28 "confirmed_at": datetime.now().strftime("%m/%d/%Y, %H:%M:%S"),
29 }
30 url = self.full_url + str(self.future_vehicle.id) + "/"
31 client = requests.Session()
32 client.auth = HTTPBasicAuth(self.admin_user.username, "test")
33 client.headers.update({"x-test": "true"})
34 response = client.get(self.live_server_url + "/admin/")
35 csrftoken = response.cookies["csrftoken"]
36 # interact with the api
37 response = client.patch(
38 url,
39 data=json.dumps(data_dict),
40 cookies=response.cookies,
41 headers={
42 "X-Requested-With": "XMLHttpRequest",
43 "X-CSRFTOKEN": csrftoken,
44 },
45 )
46 # RESPONSE GIVES 403 PERMISSION DENIED
47 fte_future_vehicle = FutureVehicle.objects.filter(
48 id=self.future_vehicle.id
49 ).first()
50 # THIS ERRORS WITH '' not equal to 'TT'
51 self.assertEqual(fte_future_vehicle.signature, "TT")
52 def test_patch_request_updates_object(self):
53 data_dict = {
54 "signature": "TT",
55 "purchasing": "true",
56 "confirmed_at": datetime.now().strftime("%m/%d/%Y, %H:%M:%S"),
57 }
58 url = self.full_url + str(self.future_vehicle.id) + "/"
59 api_req_factory = APIRequestFactory()
60 view = FutureVehicleViewSet.as_view({"patch": "partial_update"})
61 api_request = api_req_factory.patch(
62 url, json.dumps(data_dict), content_type="application/json"
63 )
64 force_authenticate(api_request, self.admin_user)
65 response = view(api_request, pk=self.future_assignment.id)
66 fte_future_assignment = FutureVehicle.objects.filter(
67 id=self.future_assignment.id
68 ).first()
69 self.assertEqual(fte_future_assignment.signature, "TT")
70
If I enter the debugger to look at the responses, it's always a 403
.
The viewset
itself is very simple:
1class FutureVehicleURLTest(APILiveServerTestCase):
2 def setUp(self):
3 # Setup users and some vehicle data we can query against
4 management.call_command("create_users_and_vehicle_data", verbosity=0)
5 self.user = UserFactory()
6 self.admin_user = User.objects.get(username="adminuser")
7 self.future_vehicle = f.FutureVehicleFactory(
8 user=self.user,
9 last_updated_by=self.user,
10 )
11 self.vehicle = f.VehicleFactory(
12 user=self.user,
13 created_by=self.user,
14 modified_by=self.user,
15 )
16 self.url = reverse("FutureVehicles-list")
17 self.full_url = self.live_server_url + self.url
18 time = str(datetime.now())
19 self.form_data = {
20 "signature": "TT",
21 "purchasing": True,
22 "confirmed_at": time,
23 }
24 def test_patch_request_updates_object(self):
25 data_dict = {
26 "signature": "TT",
27 "purchasing": "true",
28 "confirmed_at": datetime.now().strftime("%m/%d/%Y, %H:%M:%S"),
29 }
30 url = self.full_url + str(self.future_vehicle.id) + "/"
31 client = requests.Session()
32 client.auth = HTTPBasicAuth(self.admin_user.username, "test")
33 client.headers.update({"x-test": "true"})
34 response = client.get(self.live_server_url + "/admin/")
35 csrftoken = response.cookies["csrftoken"]
36 # interact with the api
37 response = client.patch(
38 url,
39 data=json.dumps(data_dict),
40 cookies=response.cookies,
41 headers={
42 "X-Requested-With": "XMLHttpRequest",
43 "X-CSRFTOKEN": csrftoken,
44 },
45 )
46 # RESPONSE GIVES 403 PERMISSION DENIED
47 fte_future_vehicle = FutureVehicle.objects.filter(
48 id=self.future_vehicle.id
49 ).first()
50 # THIS ERRORS WITH '' not equal to 'TT'
51 self.assertEqual(fte_future_vehicle.signature, "TT")
52 def test_patch_request_updates_object(self):
53 data_dict = {
54 "signature": "TT",
55 "purchasing": "true",
56 "confirmed_at": datetime.now().strftime("%m/%d/%Y, %H:%M:%S"),
57 }
58 url = self.full_url + str(self.future_vehicle.id) + "/"
59 api_req_factory = APIRequestFactory()
60 view = FutureVehicleViewSet.as_view({"patch": "partial_update"})
61 api_request = api_req_factory.patch(
62 url, json.dumps(data_dict), content_type="application/json"
63 )
64 force_authenticate(api_request, self.admin_user)
65 response = view(api_request, pk=self.future_assignment.id)
66 fte_future_assignment = FutureVehicle.objects.filter(
67 id=self.future_assignment.id
68 ).first()
69 self.assertEqual(fte_future_assignment.signature, "TT")
70class FutureVehicleViewSet(ModelViewSet):
71 serializer_class = FutureVehicleSerializer
72
73 def get_queryset(self):
74 queryset = FutureVehicle.exclude_denied.all()
75 user_id = self.request.query_params.get("user_id", None)
76 if user_id:
77 queryset = queryset.filter(user_id=user_id)
78 return queryset
79
The serializer is just as basic as it gets - it's just the FutureVehicle
model and all fields.
I just can't figure out why my user won't login - or if maybe I'm doing something wrong in my attempts to patch?
I'm pretty new to Django Rest Framework in general, so any guidances is helpful!
Edit to add - my DRF Settings look like this:
1class FutureVehicleURLTest(APILiveServerTestCase):
2 def setUp(self):
3 # Setup users and some vehicle data we can query against
4 management.call_command("create_users_and_vehicle_data", verbosity=0)
5 self.user = UserFactory()
6 self.admin_user = User.objects.get(username="adminuser")
7 self.future_vehicle = f.FutureVehicleFactory(
8 user=self.user,
9 last_updated_by=self.user,
10 )
11 self.vehicle = f.VehicleFactory(
12 user=self.user,
13 created_by=self.user,
14 modified_by=self.user,
15 )
16 self.url = reverse("FutureVehicles-list")
17 self.full_url = self.live_server_url + self.url
18 time = str(datetime.now())
19 self.form_data = {
20 "signature": "TT",
21 "purchasing": True,
22 "confirmed_at": time,
23 }
24 def test_patch_request_updates_object(self):
25 data_dict = {
26 "signature": "TT",
27 "purchasing": "true",
28 "confirmed_at": datetime.now().strftime("%m/%d/%Y, %H:%M:%S"),
29 }
30 url = self.full_url + str(self.future_vehicle.id) + "/"
31 client = requests.Session()
32 client.auth = HTTPBasicAuth(self.admin_user.username, "test")
33 client.headers.update({"x-test": "true"})
34 response = client.get(self.live_server_url + "/admin/")
35 csrftoken = response.cookies["csrftoken"]
36 # interact with the api
37 response = client.patch(
38 url,
39 data=json.dumps(data_dict),
40 cookies=response.cookies,
41 headers={
42 "X-Requested-With": "XMLHttpRequest",
43 "X-CSRFTOKEN": csrftoken,
44 },
45 )
46 # RESPONSE GIVES 403 PERMISSION DENIED
47 fte_future_vehicle = FutureVehicle.objects.filter(
48 id=self.future_vehicle.id
49 ).first()
50 # THIS ERRORS WITH '' not equal to 'TT'
51 self.assertEqual(fte_future_vehicle.signature, "TT")
52 def test_patch_request_updates_object(self):
53 data_dict = {
54 "signature": "TT",
55 "purchasing": "true",
56 "confirmed_at": datetime.now().strftime("%m/%d/%Y, %H:%M:%S"),
57 }
58 url = self.full_url + str(self.future_vehicle.id) + "/"
59 api_req_factory = APIRequestFactory()
60 view = FutureVehicleViewSet.as_view({"patch": "partial_update"})
61 api_request = api_req_factory.patch(
62 url, json.dumps(data_dict), content_type="application/json"
63 )
64 force_authenticate(api_request, self.admin_user)
65 response = view(api_request, pk=self.future_assignment.id)
66 fte_future_assignment = FutureVehicle.objects.filter(
67 id=self.future_assignment.id
68 ).first()
69 self.assertEqual(fte_future_assignment.signature, "TT")
70class FutureVehicleViewSet(ModelViewSet):
71 serializer_class = FutureVehicleSerializer
72
73 def get_queryset(self):
74 queryset = FutureVehicle.exclude_denied.all()
75 user_id = self.request.query_params.get("user_id", None)
76 if user_id:
77 queryset = queryset.filter(user_id=user_id)
78 return queryset
79REST_FRAMEWORK = {
80 "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
81 "DATETIME_FORMAT": "%m/%d/%Y - %I:%M:%S %p",
82 "DATE_INPUT_FORMATS": ["%Y-%m-%d"],
83 "DEFAULT_AUTHENTICATION_CLASSES": [
84 # Enabling this it will require Django Session (Including CSRF)
85 "rest_framework.authentication.SessionAuthentication"
86 ],
87 "DEFAULT_PERMISSION_CLASSES": [
88 # Globally only allow IsAuthenticated users access to API Endpoints
89 "rest_framework.permissions.IsAuthenticated"
90 ],
91}
92
I'm certain adminuser
is the user we wish to login - if I go into the debugger and check the users, they exist as a user. During creation, any user created has a password set to 'test'.
ANSWER
Answered 2021-Dec-11 at 07:34The test you have written is also testing the Django framework logic (ie: Django admin login). I recommend testing your own functionality, which occurs after login to the Django admin. Django's testing framework offers a helper for logging into the admin, client.login
. This allows you to focus on testing your own business logic/not need to maintain internal django authentication business logic tests, which may change release to release.
1class FutureVehicleURLTest(APILiveServerTestCase):
2 def setUp(self):
3 # Setup users and some vehicle data we can query against
4 management.call_command("create_users_and_vehicle_data", verbosity=0)
5 self.user = UserFactory()
6 self.admin_user = User.objects.get(username="adminuser")
7 self.future_vehicle = f.FutureVehicleFactory(
8 user=self.user,
9 last_updated_by=self.user,
10 )
11 self.vehicle = f.VehicleFactory(
12 user=self.user,
13 created_by=self.user,
14 modified_by=self.user,
15 )
16 self.url = reverse("FutureVehicles-list")
17 self.full_url = self.live_server_url + self.url
18 time = str(datetime.now())
19 self.form_data = {
20 "signature": "TT",
21 "purchasing": True,
22 "confirmed_at": time,
23 }
24 def test_patch_request_updates_object(self):
25 data_dict = {
26 "signature": "TT",
27 "purchasing": "true",
28 "confirmed_at": datetime.now().strftime("%m/%d/%Y, %H:%M:%S"),
29 }
30 url = self.full_url + str(self.future_vehicle.id) + "/"
31 client = requests.Session()
32 client.auth = HTTPBasicAuth(self.admin_user.username, "test")
33 client.headers.update({"x-test": "true"})
34 response = client.get(self.live_server_url + "/admin/")
35 csrftoken = response.cookies["csrftoken"]
36 # interact with the api
37 response = client.patch(
38 url,
39 data=json.dumps(data_dict),
40 cookies=response.cookies,
41 headers={
42 "X-Requested-With": "XMLHttpRequest",
43 "X-CSRFTOKEN": csrftoken,
44 },
45 )
46 # RESPONSE GIVES 403 PERMISSION DENIED
47 fte_future_vehicle = FutureVehicle.objects.filter(
48 id=self.future_vehicle.id
49 ).first()
50 # THIS ERRORS WITH '' not equal to 'TT'
51 self.assertEqual(fte_future_vehicle.signature, "TT")
52 def test_patch_request_updates_object(self):
53 data_dict = {
54 "signature": "TT",
55 "purchasing": "true",
56 "confirmed_at": datetime.now().strftime("%m/%d/%Y, %H:%M:%S"),
57 }
58 url = self.full_url + str(self.future_vehicle.id) + "/"
59 api_req_factory = APIRequestFactory()
60 view = FutureVehicleViewSet.as_view({"patch": "partial_update"})
61 api_request = api_req_factory.patch(
62 url, json.dumps(data_dict), content_type="application/json"
63 )
64 force_authenticate(api_request, self.admin_user)
65 response = view(api_request, pk=self.future_assignment.id)
66 fte_future_assignment = FutureVehicle.objects.filter(
67 id=self.future_assignment.id
68 ).first()
69 self.assertEqual(fte_future_assignment.signature, "TT")
70class FutureVehicleViewSet(ModelViewSet):
71 serializer_class = FutureVehicleSerializer
72
73 def get_queryset(self):
74 queryset = FutureVehicle.exclude_denied.all()
75 user_id = self.request.query_params.get("user_id", None)
76 if user_id:
77 queryset = queryset.filter(user_id=user_id)
78 return queryset
79REST_FRAMEWORK = {
80 "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
81 "DATETIME_FORMAT": "%m/%d/%Y - %I:%M:%S %p",
82 "DATE_INPUT_FORMATS": ["%Y-%m-%d"],
83 "DEFAULT_AUTHENTICATION_CLASSES": [
84 # Enabling this it will require Django Session (Including CSRF)
85 "rest_framework.authentication.SessionAuthentication"
86 ],
87 "DEFAULT_PERMISSION_CLASSES": [
88 # Globally only allow IsAuthenticated users access to API Endpoints
89 "rest_framework.permissions.IsAuthenticated"
90 ],
91}
92from django.test import TestCase, Client
93
94
95def TestCase():
96 client.login(username=self.username, password=self.password)
97
However, if you must replicate and manage the business logic of what client.login
is doing, here's some of the business logic from Django:
1class FutureVehicleURLTest(APILiveServerTestCase):
2 def setUp(self):
3 # Setup users and some vehicle data we can query against
4 management.call_command("create_users_and_vehicle_data", verbosity=0)
5 self.user = UserFactory()
6 self.admin_user = User.objects.get(username="adminuser")
7 self.future_vehicle = f.FutureVehicleFactory(
8 user=self.user,
9 last_updated_by=self.user,
10 )
11 self.vehicle = f.VehicleFactory(
12 user=self.user,
13 created_by=self.user,
14 modified_by=self.user,
15 )
16 self.url = reverse("FutureVehicles-list")
17 self.full_url = self.live_server_url + self.url
18 time = str(datetime.now())
19 self.form_data = {
20 "signature": "TT",
21 "purchasing": True,
22 "confirmed_at": time,
23 }
24 def test_patch_request_updates_object(self):
25 data_dict = {
26 "signature": "TT",
27 "purchasing": "true",
28 "confirmed_at": datetime.now().strftime("%m/%d/%Y, %H:%M:%S"),
29 }
30 url = self.full_url + str(self.future_vehicle.id) + "/"
31 client = requests.Session()
32 client.auth = HTTPBasicAuth(self.admin_user.username, "test")
33 client.headers.update({"x-test": "true"})
34 response = client.get(self.live_server_url + "/admin/")
35 csrftoken = response.cookies["csrftoken"]
36 # interact with the api
37 response = client.patch(
38 url,
39 data=json.dumps(data_dict),
40 cookies=response.cookies,
41 headers={
42 "X-Requested-With": "XMLHttpRequest",
43 "X-CSRFTOKEN": csrftoken,
44 },
45 )
46 # RESPONSE GIVES 403 PERMISSION DENIED
47 fte_future_vehicle = FutureVehicle.objects.filter(
48 id=self.future_vehicle.id
49 ).first()
50 # THIS ERRORS WITH '' not equal to 'TT'
51 self.assertEqual(fte_future_vehicle.signature, "TT")
52 def test_patch_request_updates_object(self):
53 data_dict = {
54 "signature": "TT",
55 "purchasing": "true",
56 "confirmed_at": datetime.now().strftime("%m/%d/%Y, %H:%M:%S"),
57 }
58 url = self.full_url + str(self.future_vehicle.id) + "/"
59 api_req_factory = APIRequestFactory()
60 view = FutureVehicleViewSet.as_view({"patch": "partial_update"})
61 api_request = api_req_factory.patch(
62 url, json.dumps(data_dict), content_type="application/json"
63 )
64 force_authenticate(api_request, self.admin_user)
65 response = view(api_request, pk=self.future_assignment.id)
66 fte_future_assignment = FutureVehicle.objects.filter(
67 id=self.future_assignment.id
68 ).first()
69 self.assertEqual(fte_future_assignment.signature, "TT")
70class FutureVehicleViewSet(ModelViewSet):
71 serializer_class = FutureVehicleSerializer
72
73 def get_queryset(self):
74 queryset = FutureVehicle.exclude_denied.all()
75 user_id = self.request.query_params.get("user_id", None)
76 if user_id:
77 queryset = queryset.filter(user_id=user_id)
78 return queryset
79REST_FRAMEWORK = {
80 "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
81 "DATETIME_FORMAT": "%m/%d/%Y - %I:%M:%S %p",
82 "DATE_INPUT_FORMATS": ["%Y-%m-%d"],
83 "DEFAULT_AUTHENTICATION_CLASSES": [
84 # Enabling this it will require Django Session (Including CSRF)
85 "rest_framework.authentication.SessionAuthentication"
86 ],
87 "DEFAULT_PERMISSION_CLASSES": [
88 # Globally only allow IsAuthenticated users access to API Endpoints
89 "rest_framework.permissions.IsAuthenticated"
90 ],
91}
92from django.test import TestCase, Client
93
94
95def TestCase():
96 client.login(username=self.username, password=self.password)
97 def login(self, **credentials):
98 """
99 Set the Factory to appear as if it has successfully logged into a site.
100 Return True if login is possible or False if the provided credentials
101 are incorrect.
102 """
103 from django.contrib.auth import authenticate
104 user = authenticate(**credentials)
105 if user:
106 self._login(user)
107 return True
108 return False
109
110 def force_login(self, user, backend=None):
111 def get_backend():
112 from django.contrib.auth import load_backend
113 for backend_path in settings.AUTHENTICATION_BACKENDS:
114 backend = load_backend(backend_path)
115 if hasattr(backend, 'get_user'):
116 return backend_path
117
118 if backend is None:
119 backend = get_backend()
120 user.backend = backend
121 self._login(user, backend)
122
123 def _login(self, user, backend=None):
124 from django.contrib.auth import login
125
126 # Create a fake request to store login details.
127 request = HttpRequest()
128 if self.session:
129 request.session = self.session
130 else:
131 engine = import_module(settings.SESSION_ENGINE)
132 request.session = engine.SessionStore()
133 login(request, user, backend)
134 # Save the session values.
135 request.session.save()
136 # Set the cookie to represent the session.
137 session_cookie = settings.SESSION_COOKIE_NAME
138 self.cookies[session_cookie] = request.session.session_key
139 cookie_data = {
140 'max-age': None,
141 'path': '/',
142 'domain': settings.SESSION_COOKIE_DOMAIN,
143 'secure': settings.SESSION_COOKIE_SECURE or None,
144 'expires': None,
145 }
146 self.cookies[session_cookie].update(cookie_data)
147
Django client.login: https://github.com/django/django/blob/main/django/test/client.py#L596-L646
QUESTION
Haskell: Can I read integers directly into an array?
Asked 2021-Dec-05 at 11:40In this programming problem, the input is an n
×m
integer matrix. Typically, n
≈ 105 and m
≈ 10. The official solution (1606D, Tutorial) is quite imperative: it involves some matrix manipulation, precomputation and aggregation. For fun, I took it as an STUArray implementation exercise.
I have managed to implement it using STUArray, but still the program takes way more memory than permitted (256MB). Even when run locally, the maximum resident set size is >400 MB. On profiling, reading from stdin seems to be dominating the memory footprint:
Functions readv
and readv.readInt
, responsible for parsing integers and saving them into a 2D list, are taking around 50-70 MB, as opposed to around 16 MB = (106 integers) × (8 bytes per integer + 8 bytes per link).
Is there a hope I can get the total memory below 256 MB? I'm already using Text
package for input. Maybe I should avoid lists altogether and directly read integers from stdin to the array. How can we do that? Or, is the issue elsewhere?
1{-# OPTIONS_GHC -O2 #-}
2module CF1606D where
3import qualified Data.Text as T
4import qualified Data.Text.IO as TI
5import qualified Data.Text.Read as TR
6import Control.Monad
7import qualified Data.List as DL
8import qualified Data.IntSet as DS
9import Control.Monad.ST
10import Data.Array.ST.Safe
11import Data.Int (Int32)
12import Data.Array.Unboxed
13
14solve :: IO ()
15solve = do
16 ~[n,m] <- readv
17 -- 2D list
18 input <- {-# SCC input #-} replicateM (fromIntegral n) readv
19 let
20 ints = [1..]
21 sorted = DL.sortOn (head.fst) (zip input ints)
22 (rows,indices) = {-# SCC rows_inds #-} unzip sorted
23 -- 2D list converted into matrix:
24 matrix = mat (fromIntegral n) (fromIntegral m) rows
25 infinite = 10^7
26 asc x y = [x,x+1..y]
27 desc x y = [y,y-1..x]
28 -- Four prefix-matrices:
29 tlMax = runSTUArray $ prefixMat max 0 asc asc (subtract 1) (subtract 1) =<< matrix
30 blMin = runSTUArray $ prefixMat min infinite desc asc (+1) (subtract 1) =<< matrix
31 trMin = runSTUArray $ prefixMat min infinite asc desc (subtract 1) (+1) =<< matrix
32 brMax = runSTUArray $ prefixMat max 0 desc desc (+1) (+1) =<< matrix
33 good _ (i,j)
34 | tlMax!(i,j) < blMin!(i+1,j) && brMax!(i+1,j+1) < trMin!(i,j+1) = Left (i,j)
35 | otherwise = Right ()
36 {-# INLINABLE good #-}
37 nearAns = foldM good () [(i,j)|i<-[1..n-1],j<-[1..m-1]]
38 ans = either (\(i,j)-> "YES\n" ++ color n (take i indices) ++ " " ++ show j) (const "NO") nearAns
39 putStrLn ans
40
41type I = Int32
42type S s = (STUArray s (Int, Int) I)
43type R = Int -> Int -> [Int]
44type F = Int -> Int
45
46mat :: Int -> Int -> [[I]] -> ST s (S s)
47mat n m rows = newListArray ((1,1),(n,m)) $ concat rows
48
49prefixMat :: (I->I->I) -> I -> R -> R -> F -> F -> S s -> ST s (S s)
50prefixMat opt worst ordi ordj previ prevj mat = do
51 ((ilo,jlo),(ihi,jhi)) <- getBounds mat
52 pre <- newArray ((ilo-1,jlo-1),(ihi+1,jhi+1)) worst
53 forM_ (ordi ilo ihi) $ \i-> do
54 forM_ (ordj jlo jhi) $ \j -> do
55 matij <- readArray mat (i,j)
56 prei <- readArray pre (previ i,j)
57 prej <- readArray pre (i, prevj j)
58 writeArray pre (i,j) (opt (opt prei prej) matij)
59 return pre
60
61color :: Int -> [Int] -> String
62color n inds = let
63 temp = DS.fromList inds
64 colors = [if DS.member i temp then 'B' else 'R' | i<-[1..n]]
65 in colors
66
67readv :: Integral t => IO [t]
68readv = map readInt . T.words <$> TI.getLine where
69 readInt = fromIntegral . either (const 0) fst . TR.signed TR.decimal
70{-# INLINABLE readv #-}
71
72main :: IO ()
73main = do
74 ~[n] <- readv
75 replicateM_ n solve
76
Quick description of the code above:
n
rows each having m
integers.Sample input and Commands
Sample input: inp3.txt.
Command:
1{-# OPTIONS_GHC -O2 #-}
2module CF1606D where
3import qualified Data.Text as T
4import qualified Data.Text.IO as TI
5import qualified Data.Text.Read as TR
6import Control.Monad
7import qualified Data.List as DL
8import qualified Data.IntSet as DS
9import Control.Monad.ST
10import Data.Array.ST.Safe
11import Data.Int (Int32)
12import Data.Array.Unboxed
13
14solve :: IO ()
15solve = do
16 ~[n,m] <- readv
17 -- 2D list
18 input <- {-# SCC input #-} replicateM (fromIntegral n) readv
19 let
20 ints = [1..]
21 sorted = DL.sortOn (head.fst) (zip input ints)
22 (rows,indices) = {-# SCC rows_inds #-} unzip sorted
23 -- 2D list converted into matrix:
24 matrix = mat (fromIntegral n) (fromIntegral m) rows
25 infinite = 10^7
26 asc x y = [x,x+1..y]
27 desc x y = [y,y-1..x]
28 -- Four prefix-matrices:
29 tlMax = runSTUArray $ prefixMat max 0 asc asc (subtract 1) (subtract 1) =<< matrix
30 blMin = runSTUArray $ prefixMat min infinite desc asc (+1) (subtract 1) =<< matrix
31 trMin = runSTUArray $ prefixMat min infinite asc desc (subtract 1) (+1) =<< matrix
32 brMax = runSTUArray $ prefixMat max 0 desc desc (+1) (+1) =<< matrix
33 good _ (i,j)
34 | tlMax!(i,j) < blMin!(i+1,j) && brMax!(i+1,j+1) < trMin!(i,j+1) = Left (i,j)
35 | otherwise = Right ()
36 {-# INLINABLE good #-}
37 nearAns = foldM good () [(i,j)|i<-[1..n-1],j<-[1..m-1]]
38 ans = either (\(i,j)-> "YES\n" ++ color n (take i indices) ++ " " ++ show j) (const "NO") nearAns
39 putStrLn ans
40
41type I = Int32
42type S s = (STUArray s (Int, Int) I)
43type R = Int -> Int -> [Int]
44type F = Int -> Int
45
46mat :: Int -> Int -> [[I]] -> ST s (S s)
47mat n m rows = newListArray ((1,1),(n,m)) $ concat rows
48
49prefixMat :: (I->I->I) -> I -> R -> R -> F -> F -> S s -> ST s (S s)
50prefixMat opt worst ordi ordj previ prevj mat = do
51 ((ilo,jlo),(ihi,jhi)) <- getBounds mat
52 pre <- newArray ((ilo-1,jlo-1),(ihi+1,jhi+1)) worst
53 forM_ (ordi ilo ihi) $ \i-> do
54 forM_ (ordj jlo jhi) $ \j -> do
55 matij <- readArray mat (i,j)
56 prei <- readArray pre (previ i,j)
57 prej <- readArray pre (i, prevj j)
58 writeArray pre (i,j) (opt (opt prei prej) matij)
59 return pre
60
61color :: Int -> [Int] -> String
62color n inds = let
63 temp = DS.fromList inds
64 colors = [if DS.member i temp then 'B' else 'R' | i<-[1..n]]
65 in colors
66
67readv :: Integral t => IO [t]
68readv = map readInt . T.words <$> TI.getLine where
69 readInt = fromIntegral . either (const 0) fst . TR.signed TR.decimal
70{-# INLINABLE readv #-}
71
72main :: IO ()
73main = do
74 ~[n] <- readv
75 replicateM_ n solve
76> stack ghc -- -main-is CF1606D.main -with-rtsopts="-s -h -p -P" -rtsopts -prof -fprof-auto CF1606D
77> gtime -v ./CF1606D < inp3.txt > outp
78 ...
79 ...
80 MUT time 2.990s ( 3.744s elapsed) # RTS -s output
81 GC time 4.525s ( 6.231s elapsed) # RTS -s output
82 ...
83 ...
84 Maximum resident set size (kbytes): 408532 # >256 MB (gtime output)
85
86> stack exec -- hp2ps -t0.1 -e8in -c CF1606D.hp && open CF1606D.ps
87
Question about GC: As shown above in the +RTS -s output, GC seems to be taking longer than the actual logic execution. Is this normal? Is there a way to visualize the GC activity over time? I tried making matrices strict but that didn't have any impact.
Probably this is not a functional-friendly problem at all (although I'll be happy to be disproved on this). For example, Java uses GC too but there are lots of successful Java submissions. Still, I want to see how far I can push. Thanks!
ANSWER
Answered 2021-Dec-05 at 11:40Contrary to common belief Haskell is quite friendly with respect to problems like that. The real issue is that the array
library that comes with GHC is total garbage. Another big problem is that everyone is taught in Haskell to use lists where arrays should be used instead, which is usually one of the major sources of slow code and memory bloated programs. So, it is not surprising that GC takes a long time, it is because there is way too much stuff being allocation. Here is a run on the supplied input for the solution provided below:
1{-# OPTIONS_GHC -O2 #-}
2module CF1606D where
3import qualified Data.Text as T
4import qualified Data.Text.IO as TI
5import qualified Data.Text.Read as TR
6import Control.Monad
7import qualified Data.List as DL
8import qualified Data.IntSet as DS
9import Control.Monad.ST
10import Data.Array.ST.Safe
11import Data.Int (Int32)
12import Data.Array.Unboxed
13
14solve :: IO ()
15solve = do
16 ~[n,m] <- readv
17 -- 2D list
18 input <- {-# SCC input #-} replicateM (fromIntegral n) readv
19 let
20 ints = [1..]
21 sorted = DL.sortOn (head.fst) (zip input ints)
22 (rows,indices) = {-# SCC rows_inds #-} unzip sorted
23 -- 2D list converted into matrix:
24 matrix = mat (fromIntegral n) (fromIntegral m) rows
25 infinite = 10^7
26 asc x y = [x,x+1..y]
27 desc x y = [y,y-1..x]
28 -- Four prefix-matrices:
29 tlMax = runSTUArray $ prefixMat max 0 asc asc (subtract 1) (subtract 1) =<< matrix
30 blMin = runSTUArray $ prefixMat min infinite desc asc (+1) (subtract 1) =<< matrix
31 trMin = runSTUArray $ prefixMat min infinite asc desc (subtract 1) (+1) =<< matrix
32 brMax = runSTUArray $ prefixMat max 0 desc desc (+1) (+1) =<< matrix
33 good _ (i,j)
34 | tlMax!(i,j) < blMin!(i+1,j) && brMax!(i+1,j+1) < trMin!(i,j+1) = Left (i,j)
35 | otherwise = Right ()
36 {-# INLINABLE good #-}
37 nearAns = foldM good () [(i,j)|i<-[1..n-1],j<-[1..m-1]]
38 ans = either (\(i,j)-> "YES\n" ++ color n (take i indices) ++ " " ++ show j) (const "NO") nearAns
39 putStrLn ans
40
41type I = Int32
42type S s = (STUArray s (Int, Int) I)
43type R = Int -> Int -> [Int]
44type F = Int -> Int
45
46mat :: Int -> Int -> [[I]] -> ST s (S s)
47mat n m rows = newListArray ((1,1),(n,m)) $ concat rows
48
49prefixMat :: (I->I->I) -> I -> R -> R -> F -> F -> S s -> ST s (S s)
50prefixMat opt worst ordi ordj previ prevj mat = do
51 ((ilo,jlo),(ihi,jhi)) <- getBounds mat
52 pre <- newArray ((ilo-1,jlo-1),(ihi+1,jhi+1)) worst
53 forM_ (ordi ilo ihi) $ \i-> do
54 forM_ (ordj jlo jhi) $ \j -> do
55 matij <- readArray mat (i,j)
56 prei <- readArray pre (previ i,j)
57 prej <- readArray pre (i, prevj j)
58 writeArray pre (i,j) (opt (opt prei prej) matij)
59 return pre
60
61color :: Int -> [Int] -> String
62color n inds = let
63 temp = DS.fromList inds
64 colors = [if DS.member i temp then 'B' else 'R' | i<-[1..n]]
65 in colors
66
67readv :: Integral t => IO [t]
68readv = map readInt . T.words <$> TI.getLine where
69 readInt = fromIntegral . either (const 0) fst . TR.signed TR.decimal
70{-# INLINABLE readv #-}
71
72main :: IO ()
73main = do
74 ~[n] <- readv
75 replicateM_ n solve
76> stack ghc -- -main-is CF1606D.main -with-rtsopts="-s -h -p -P" -rtsopts -prof -fprof-auto CF1606D
77> gtime -v ./CF1606D < inp3.txt > outp
78 ...
79 ...
80 MUT time 2.990s ( 3.744s elapsed) # RTS -s output
81 GC time 4.525s ( 6.231s elapsed) # RTS -s output
82 ...
83 ...
84 Maximum resident set size (kbytes): 408532 # >256 MB (gtime output)
85
86> stack exec -- hp2ps -t0.1 -e8in -c CF1606D.hp && open CF1606D.ps
87 1,483,547,096 bytes allocated in the heap
88 566,448 bytes copied during GC
89 18,703,640 bytes maximum residency (3 sample(s))
90 1,223,400 bytes maximum slop
91 32 MiB total memory in use (0 MB lost due to fragmentation)
92
93 Tot time (elapsed) Avg pause Max pause
94 Gen 0 1399 colls, 0 par 0.009s 0.009s 0.0000s 0.0011s
95 Gen 1 3 colls, 0 par 0.002s 0.002s 0.0006s 0.0016s
96
97 TASKS: 4 (1 bound, 3 peak workers (3 total), using -N1)
98
99 SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)
100
101 INIT time 0.001s ( 0.001s elapsed)
102 MUT time 0.484s ( 0.517s elapsed)
103 GC time 0.011s ( 0.011s elapsed)
104 EXIT time 0.001s ( 0.002s elapsed)
105 Total time 0.496s ( 0.530s elapsed)
106
The solution provided below uses an array library massiv
, which makes it impossible to submit to codeforces. However, hopefully the goal is to get better at Haskell, rather than get points on some website.
The red-blue matrix can be separated into two stages: read and solve
Read Read the dimensionsIn the main
function we only read total number of arrays and dimensions for each array. Also we print the outcome. Nothing exciting here. (Note that the linked file inp3.txt
has a larger array than the limits defined in the problem: n*m <= 10^6
)
1{-# OPTIONS_GHC -O2 #-}
2module CF1606D where
3import qualified Data.Text as T
4import qualified Data.Text.IO as TI
5import qualified Data.Text.Read as TR
6import Control.Monad
7import qualified Data.List as DL
8import qualified Data.IntSet as DS
9import Control.Monad.ST
10import Data.Array.ST.Safe
11import Data.Int (Int32)
12import Data.Array.Unboxed
13
14solve :: IO ()
15solve = do
16 ~[n,m] <- readv
17 -- 2D list
18 input <- {-# SCC input #-} replicateM (fromIntegral n) readv
19 let
20 ints = [1..]
21 sorted = DL.sortOn (head.fst) (zip input ints)
22 (rows,indices) = {-# SCC rows_inds #-} unzip sorted
23 -- 2D list converted into matrix:
24 matrix = mat (fromIntegral n) (fromIntegral m) rows
25 infinite = 10^7
26 asc x y = [x,x+1..y]
27 desc x y = [y,y-1..x]
28 -- Four prefix-matrices:
29 tlMax = runSTUArray $ prefixMat max 0 asc asc (subtract 1) (subtract 1) =<< matrix
30 blMin = runSTUArray $ prefixMat min infinite desc asc (+1) (subtract 1) =<< matrix
31 trMin = runSTUArray $ prefixMat min infinite asc desc (subtract 1) (+1) =<< matrix
32 brMax = runSTUArray $ prefixMat max 0 desc desc (+1) (+1) =<< matrix
33 good _ (i,j)
34 | tlMax!(i,j) < blMin!(i+1,j) && brMax!(i+1,j+1) < trMin!(i,j+1) = Left (i,j)
35 | otherwise = Right ()
36 {-# INLINABLE good #-}
37 nearAns = foldM good () [(i,j)|i<-[1..n-1],j<-[1..m-1]]
38 ans = either (\(i,j)-> "YES\n" ++ color n (take i indices) ++ " " ++ show j) (const "NO") nearAns
39 putStrLn ans
40
41type I = Int32
42type S s = (STUArray s (Int, Int) I)
43type R = Int -> Int -> [Int]
44type F = Int -> Int
45
46mat :: Int -> Int -> [[I]] -> ST s (S s)
47mat n m rows = newListArray ((1,1),(n,m)) $ concat rows
48
49prefixMat :: (I->I->I) -> I -> R -> R -> F -> F -> S s -> ST s (S s)
50prefixMat opt worst ordi ordj previ prevj mat = do
51 ((ilo,jlo),(ihi,jhi)) <- getBounds mat
52 pre <- newArray ((ilo-1,jlo-1),(ihi+1,jhi+1)) worst
53 forM_ (ordi ilo ihi) $ \i-> do
54 forM_ (ordj jlo jhi) $ \j -> do
55 matij <- readArray mat (i,j)
56 prei <- readArray pre (previ i,j)
57 prej <- readArray pre (i, prevj j)
58 writeArray pre (i,j) (opt (opt prei prej) matij)
59 return pre
60
61color :: Int -> [Int] -> String
62color n inds = let
63 temp = DS.fromList inds
64 colors = [if DS.member i temp then 'B' else 'R' | i<-[1..n]]
65 in colors
66
67readv :: Integral t => IO [t]
68readv = map readInt . T.words <$> TI.getLine where
69 readInt = fromIntegral . either (const 0) fst . TR.signed TR.decimal
70{-# INLINABLE readv #-}
71
72main :: IO ()
73main = do
74 ~[n] <- readv
75 replicateM_ n solve
76> stack ghc -- -main-is CF1606D.main -with-rtsopts="-s -h -p -P" -rtsopts -prof -fprof-auto CF1606D
77> gtime -v ./CF1606D < inp3.txt > outp
78 ...
79 ...
80 MUT time 2.990s ( 3.744s elapsed) # RTS -s output
81 GC time 4.525s ( 6.231s elapsed) # RTS -s output
82 ...
83 ...
84 Maximum resident set size (kbytes): 408532 # >256 MB (gtime output)
85
86> stack exec -- hp2ps -t0.1 -e8in -c CF1606D.hp && open CF1606D.ps
87 1,483,547,096 bytes allocated in the heap
88 566,448 bytes copied during GC
89 18,703,640 bytes maximum residency (3 sample(s))
90 1,223,400 bytes maximum slop
91 32 MiB total memory in use (0 MB lost due to fragmentation)
92
93 Tot time (elapsed) Avg pause Max pause
94 Gen 0 1399 colls, 0 par 0.009s 0.009s 0.0000s 0.0011s
95 Gen 1 3 colls, 0 par 0.002s 0.002s 0.0006s 0.0016s
96
97 TASKS: 4 (1 bound, 3 peak workers (3 total), using -N1)
98
99 SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)
100
101 INIT time 0.001s ( 0.001s elapsed)
102 MUT time 0.484s ( 0.517s elapsed)
103 GC time 0.011s ( 0.011s elapsed)
104 EXIT time 0.001s ( 0.002s elapsed)
105 Total time 0.496s ( 0.530s elapsed)
106import Control.Monad.ST
107import Control.Monad
108import qualified Data.ByteString as BS
109import Data.Massiv.Array as A hiding (B)
110import Data.Massiv.Array.Mutable.Algorithms (quicksortByM_)
111import Control.Scheduler (trivialScheduler_)
112
113main :: IO ()
114main = do
115 t <- Prelude.read <$> getLine
116 when (t < 1 || t > 1000) $ error $ "Invalid t: " ++ show t
117 replicateM_ t $ do
118 dimsStr <- getLine
119 case Prelude.map Prelude.read (words dimsStr) of
120 -- Test file fails this check: && n * m <= 10 ^ (6 :: Int) -> do
121 [n, m] | n >= 2 && m > 0 && m <= 5 * 10 ^ (5 :: Int) -> do
122 mat <- readMatrix n m
123 case solve mat of
124 Nothing -> putStrLn "NO"
125 Just (ix, cs) -> do
126 putStrLn "YES"
127 putStr $ foldMap show cs
128 putStr " "
129 print ix
130 _ -> putStrLn $ "Unexpected dimensions: " ++ show dimsStr
131
Loading the input into array is the major source of problems int the original question:
text
, ascii characters is the only valid input expected by the problem.Normally in such situation it would be much better to read input in a streaming fashion using something like conduit
. In particular, reading input as stream of bytes and parsing those bytes as numbers would be the optimal solution. That being said there are hard requirements on the width of each array in the description of the problem, so we can get away with reading input line-by-line as a ByteString
and then parsing numbers (assumed unsigned for simplicity) in each line and write those numbers into array at the same time. This ensures that at this stage we will only have allocated the resulting array and a single line as sequence of bytes. This could be done cleaner with a parsing library like attoparsec
, but problem is simple enough to just do it adhoc.
1{-# OPTIONS_GHC -O2 #-}
2module CF1606D where
3import qualified Data.Text as T
4import qualified Data.Text.IO as TI
5import qualified Data.Text.Read as TR
6import Control.Monad
7import qualified Data.List as DL
8import qualified Data.IntSet as DS
9import Control.Monad.ST
10import Data.Array.ST.Safe
11import Data.Int (Int32)
12import Data.Array.Unboxed
13
14solve :: IO ()
15solve = do
16 ~[n,m] <- readv
17 -- 2D list
18 input <- {-# SCC input #-} replicateM (fromIntegral n) readv
19 let
20 ints = [1..]
21 sorted = DL.sortOn (head.fst) (zip input ints)
22 (rows,indices) = {-# SCC rows_inds #-} unzip sorted
23 -- 2D list converted into matrix:
24 matrix = mat (fromIntegral n) (fromIntegral m) rows
25 infinite = 10^7
26 asc x y = [x,x+1..y]
27 desc x y = [y,y-1..x]
28 -- Four prefix-matrices:
29 tlMax = runSTUArray $ prefixMat max 0 asc asc (subtract 1) (subtract 1) =<< matrix
30 blMin = runSTUArray $ prefixMat min infinite desc asc (+1) (subtract 1) =<< matrix
31 trMin = runSTUArray $ prefixMat min infinite asc desc (subtract 1) (+1) =<< matrix
32 brMax = runSTUArray $ prefixMat max 0 desc desc (+1) (+1) =<< matrix
33 good _ (i,j)
34 | tlMax!(i,j) < blMin!(i+1,j) && brMax!(i+1,j+1) < trMin!(i,j+1) = Left (i,j)
35 | otherwise = Right ()
36 {-# INLINABLE good #-}
37 nearAns = foldM good () [(i,j)|i<-[1..n-1],j<-[1..m-1]]
38 ans = either (\(i,j)-> "YES\n" ++ color n (take i indices) ++ " " ++ show j) (const "NO") nearAns
39 putStrLn ans
40
41type I = Int32
42type S s = (STUArray s (Int, Int) I)
43type R = Int -> Int -> [Int]
44type F = Int -> Int
45
46mat :: Int -> Int -> [[I]] -> ST s (S s)
47mat n m rows = newListArray ((1,1),(n,m)) $ concat rows
48
49prefixMat :: (I->I->I) -> I -> R -> R -> F -> F -> S s -> ST s (S s)
50prefixMat opt worst ordi ordj previ prevj mat = do
51 ((ilo,jlo),(ihi,jhi)) <- getBounds mat
52 pre <- newArray ((ilo-1,jlo-1),(ihi+1,jhi+1)) worst
53 forM_ (ordi ilo ihi) $ \i-> do
54 forM_ (ordj jlo jhi) $ \j -> do
55 matij <- readArray mat (i,j)
56 prei <- readArray pre (previ i,j)
57 prej <- readArray pre (i, prevj j)
58 writeArray pre (i,j) (opt (opt prei prej) matij)
59 return pre
60
61color :: Int -> [Int] -> String
62color n inds = let
63 temp = DS.fromList inds
64 colors = [if DS.member i temp then 'B' else 'R' | i<-[1..n]]
65 in colors
66
67readv :: Integral t => IO [t]
68readv = map readInt . T.words <$> TI.getLine where
69 readInt = fromIntegral . either (const 0) fst . TR.signed TR.decimal
70{-# INLINABLE readv #-}
71
72main :: IO ()
73main = do
74 ~[n] <- readv
75 replicateM_ n solve
76> stack ghc -- -main-is CF1606D.main -with-rtsopts="-s -h -p -P" -rtsopts -prof -fprof-auto CF1606D
77> gtime -v ./CF1606D < inp3.txt > outp
78 ...
79 ...
80 MUT time 2.990s ( 3.744s elapsed) # RTS -s output
81 GC time 4.525s ( 6.231s elapsed) # RTS -s output
82 ...
83 ...
84 Maximum resident set size (kbytes): 408532 # >256 MB (gtime output)
85
86> stack exec -- hp2ps -t0.1 -e8in -c CF1606D.hp && open CF1606D.ps
87 1,483,547,096 bytes allocated in the heap
88 566,448 bytes copied during GC
89 18,703,640 bytes maximum residency (3 sample(s))
90 1,223,400 bytes maximum slop
91 32 MiB total memory in use (0 MB lost due to fragmentation)
92
93 Tot time (elapsed) Avg pause Max pause
94 Gen 0 1399 colls, 0 par 0.009s 0.009s 0.0000s 0.0011s
95 Gen 1 3 colls, 0 par 0.002s 0.002s 0.0006s 0.0016s
96
97 TASKS: 4 (1 bound, 3 peak workers (3 total), using -N1)
98
99 SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)
100
101 INIT time 0.001s ( 0.001s elapsed)
102 MUT time 0.484s ( 0.517s elapsed)
103 GC time 0.011s ( 0.011s elapsed)
104 EXIT time 0.001s ( 0.002s elapsed)
105 Total time 0.496s ( 0.530s elapsed)
106import Control.Monad.ST
107import Control.Monad
108import qualified Data.ByteString as BS
109import Data.Massiv.Array as A hiding (B)
110import Data.Massiv.Array.Mutable.Algorithms (quicksortByM_)
111import Control.Scheduler (trivialScheduler_)
112
113main :: IO ()
114main = do
115 t <- Prelude.read <$> getLine
116 when (t < 1 || t > 1000) $ error $ "Invalid t: " ++ show t
117 replicateM_ t $ do
118 dimsStr <- getLine
119 case Prelude.map Prelude.read (words dimsStr) of
120 -- Test file fails this check: && n * m <= 10 ^ (6 :: Int) -> do
121 [n, m] | n >= 2 && m > 0 && m <= 5 * 10 ^ (5 :: Int) -> do
122 mat <- readMatrix n m
123 case solve mat of
124 Nothing -> putStrLn "NO"
125 Just (ix, cs) -> do
126 putStrLn "YES"
127 putStr $ foldMap show cs
128 putStr " "
129 print ix
130 _ -> putStrLn $ "Unexpected dimensions: " ++ show dimsStr
131type Val = Word
132
133readMatrix :: Int -> Int -> IO (Matrix P Val)
134readMatrix n m = createArrayS_ (Sz2 n m) readMMatrix
135
136readMMatrix :: MMatrix RealWorld P Val -> IO ()
137readMMatrix mat =
138 loopM_ 0 (< n) (+ 1) $ \i -> do
139 line <- BS.getLine
140 --- ^ reads at most 10Mb because it is known that input will be at most
141 -- 5*10^5 Words: 19 digits max per Word and one for space: 5*10^5 * 20bytes
142 loopM 0 (< m) (+ 1) line $ \j bs ->
143 let (word, bs') = parseWord bs
144 in bs' <$ write_ mat (i :. j) word
145 where
146 Sz2 n m = sizeOfMArray mat
147 isSpace = (== 32)
148 isDigit w8 = w8 >= 48 && w8 <= 57
149 parseWord bs =
150 case BS.uncons bs of
151 Just (w8, bs')
152 | isDigit w8 -> parseWordLoop (fromIntegral (w8 - 48)) bs'
153 | otherwise -> error $ "Unexpected byte: " ++ show w8
154 Nothing -> error "Unexpected end of input"
155 parseWordLoop !acc bs =
156 case BS.uncons bs of
157 Nothing -> (acc, bs)
158 Just (w8, bs')
159 | isSpace w8 -> (acc, bs')
160 | isDigit w8 -> parseWordLoop (acc * 10 + fromIntegral (w8 - 48)) bs'
161 | otherwise -> error $ "Unexpected byte: " ++ show w8
162
This is the step where we implement the actual solution. Instead of going into trying to fix the solution provided in this SO question I went on and translated the C++ solution that was linked in the question instead. Reason I went that route is twofold:
Note, that it should be possible to rewrite the solution below with array
package, because in the end all that is needed are the read
, write
and allocate
operations.
1{-# OPTIONS_GHC -O2 #-}
2module CF1606D where
3import qualified Data.Text as T
4import qualified Data.Text.IO as TI
5import qualified Data.Text.Read as TR
6import Control.Monad
7import qualified Data.List as DL
8import qualified Data.IntSet as DS
9import Control.Monad.ST
10import Data.Array.ST.Safe
11import Data.Int (Int32)
12import Data.Array.Unboxed
13
14solve :: IO ()
15solve = do
16 ~[n,m] <- readv
17 -- 2D list
18 input <- {-# SCC input #-} replicateM (fromIntegral n) readv
19 let
20 ints = [1..]
21 sorted = DL.sortOn (head.fst) (zip input ints)
22 (rows,indices) = {-# SCC rows_inds #-} unzip sorted
23 -- 2D list converted into matrix:
24 matrix = mat (fromIntegral n) (fromIntegral m) rows
25 infinite = 10^7
26 asc x y = [x,x+1..y]
27 desc x y = [y,y-1..x]
28 -- Four prefix-matrices:
29 tlMax = runSTUArray $ prefixMat max 0 asc asc (subtract 1) (subtract 1) =<< matrix
30 blMin = runSTUArray $ prefixMat min infinite desc asc (+1) (subtract 1) =<< matrix
31 trMin = runSTUArray $ prefixMat min infinite asc desc (subtract 1) (+1) =<< matrix
32 brMax = runSTUArray $ prefixMat max 0 desc desc (+1) (+1) =<< matrix
33 good _ (i,j)
34 | tlMax!(i,j) < blMin!(i+1,j) && brMax!(i+1,j+1) < trMin!(i,j+1) = Left (i,j)
35 | otherwise = Right ()
36 {-# INLINABLE good #-}
37 nearAns = foldM good () [(i,j)|i<-[1..n-1],j<-[1..m-1]]
38 ans = either (\(i,j)-> "YES\n" ++ color n (take i indices) ++ " " ++ show j) (const "NO") nearAns
39 putStrLn ans
40
41type I = Int32
42type S s = (STUArray s (Int, Int) I)
43type R = Int -> Int -> [Int]
44type F = Int -> Int
45
46mat :: Int -> Int -> [[I]] -> ST s (S s)
47mat n m rows = newListArray ((1,1),(n,m)) $ concat rows
48
49prefixMat :: (I->I->I) -> I -> R -> R -> F -> F -> S s -> ST s (S s)
50prefixMat opt worst ordi ordj previ prevj mat = do
51 ((ilo,jlo),(ihi,jhi)) <- getBounds mat
52 pre <- newArray ((ilo-1,jlo-1),(ihi+1,jhi+1)) worst
53 forM_ (ordi ilo ihi) $ \i-> do
54 forM_ (ordj jlo jhi) $ \j -> do
55 matij <- readArray mat (i,j)
56 prei <- readArray pre (previ i,j)
57 prej <- readArray pre (i, prevj j)
58 writeArray pre (i,j) (opt (opt prei prej) matij)
59 return pre
60
61color :: Int -> [Int] -> String
62color n inds = let
63 temp = DS.fromList inds
64 colors = [if DS.member i temp then 'B' else 'R' | i<-[1..n]]
65 in colors
66
67readv :: Integral t => IO [t]
68readv = map readInt . T.words <$> TI.getLine where
69 readInt = fromIntegral . either (const 0) fst . TR.signed TR.decimal
70{-# INLINABLE readv #-}
71
72main :: IO ()
73main = do
74 ~[n] <- readv
75 replicateM_ n solve
76> stack ghc -- -main-is CF1606D.main -with-rtsopts="-s -h -p -P" -rtsopts -prof -fprof-auto CF1606D
77> gtime -v ./CF1606D < inp3.txt > outp
78 ...
79 ...
80 MUT time 2.990s ( 3.744s elapsed) # RTS -s output
81 GC time 4.525s ( 6.231s elapsed) # RTS -s output
82 ...
83 ...
84 Maximum resident set size (kbytes): 408532 # >256 MB (gtime output)
85
86> stack exec -- hp2ps -t0.1 -e8in -c CF1606D.hp && open CF1606D.ps
87 1,483,547,096 bytes allocated in the heap
88 566,448 bytes copied during GC
89 18,703,640 bytes maximum residency (3 sample(s))
90 1,223,400 bytes maximum slop
91 32 MiB total memory in use (0 MB lost due to fragmentation)
92
93 Tot time (elapsed) Avg pause Max pause
94 Gen 0 1399 colls, 0 par 0.009s 0.009s 0.0000s 0.0011s
95 Gen 1 3 colls, 0 par 0.002s 0.002s 0.0006s 0.0016s
96
97 TASKS: 4 (1 bound, 3 peak workers (3 total), using -N1)
98
99 SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)
100
101 INIT time 0.001s ( 0.001s elapsed)
102 MUT time 0.484s ( 0.517s elapsed)
103 GC time 0.011s ( 0.011s elapsed)
104 EXIT time 0.001s ( 0.002s elapsed)
105 Total time 0.496s ( 0.530s elapsed)
106import Control.Monad.ST
107import Control.Monad
108import qualified Data.ByteString as BS
109import Data.Massiv.Array as A hiding (B)
110import Data.Massiv.Array.Mutable.Algorithms (quicksortByM_)
111import Control.Scheduler (trivialScheduler_)
112
113main :: IO ()
114main = do
115 t <- Prelude.read <$> getLine
116 when (t < 1 || t > 1000) $ error $ "Invalid t: " ++ show t
117 replicateM_ t $ do
118 dimsStr <- getLine
119 case Prelude.map Prelude.read (words dimsStr) of
120 -- Test file fails this check: && n * m <= 10 ^ (6 :: Int) -> do
121 [n, m] | n >= 2 && m > 0 && m <= 5 * 10 ^ (5 :: Int) -> do
122 mat <- readMatrix n m
123 case solve mat of
124 Nothing -> putStrLn "NO"
125 Just (ix, cs) -> do
126 putStrLn "YES"
127 putStr $ foldMap show cs
128 putStr " "
129 print ix
130 _ -> putStrLn $ "Unexpected dimensions: " ++ show dimsStr
131type Val = Word
132
133readMatrix :: Int -> Int -> IO (Matrix P Val)
134readMatrix n m = createArrayS_ (Sz2 n m) readMMatrix
135
136readMMatrix :: MMatrix RealWorld P Val -> IO ()
137readMMatrix mat =
138 loopM_ 0 (< n) (+ 1) $ \i -> do
139 line <- BS.getLine
140 --- ^ reads at most 10Mb because it is known that input will be at most
141 -- 5*10^5 Words: 19 digits max per Word and one for space: 5*10^5 * 20bytes
142 loopM 0 (< m) (+ 1) line $ \j bs ->
143 let (word, bs') = parseWord bs
144 in bs' <$ write_ mat (i :. j) word
145 where
146 Sz2 n m = sizeOfMArray mat
147 isSpace = (== 32)
148 isDigit w8 = w8 >= 48 && w8 <= 57
149 parseWord bs =
150 case BS.uncons bs of
151 Just (w8, bs')
152 | isDigit w8 -> parseWordLoop (fromIntegral (w8 - 48)) bs'
153 | otherwise -> error $ "Unexpected byte: " ++ show w8
154 Nothing -> error "Unexpected end of input"
155 parseWordLoop !acc bs =
156 case BS.uncons bs of
157 Nothing -> (acc, bs)
158 Just (w8, bs')
159 | isSpace w8 -> (acc, bs')
160 | isDigit w8 -> parseWordLoop (acc * 10 + fromIntegral (w8 - 48)) bs'
161 | otherwise -> error $ "Unexpected byte: " ++ show w8
162computeSortBy ::
163 (Load r Ix1 e, Manifest r' e)
164 => (e -> e -> Ordering)
165 -> Vector r e
166 -> Vector r' e
167computeSortBy f vec =
168 withLoadMArrayST_ vec $ quicksortByM_ (\x y -> pure $ f x y) trivialScheduler_
169
170solve :: Matrix P Val -> Maybe (Int, [Color])
171solve a = runST $ do
172 let sz@(Sz2 n m) = size a
173 ord :: Vector P Int
174 ord = computeSortBy
175 (\x y -> compare (a ! (y :. 0)) (a ! (x :. 0))) (0 ..: n)
176 mxl <- newMArray @P sz minBound
177 loopM_ (n - 1) (>= 0) (subtract 1) $ \ i ->
178 loopM_ 0 (< m) (+ 1) $ \j -> do
179 writeM mxl (i :. j) (a ! ((ord ! i) :. j))
180 when (i < n - 1) $
181 writeM mxl (i :. j)
182 =<< max <$> readM mxl (i :. j) <*> readM mxl (i + 1 :. j)
183 when (j > 0) $
184 writeM mxl (i :. j)
185 =<< max <$> readM mxl (i :. j) <*> readM mxl (i :. j - 1)
186 mnr <- newMArray @P sz maxBound
187 loopM_ (n - 1) (>= 0) (subtract 1) $ \ i ->
188 loopM_ (m - 1) (>= 0) (subtract 1) $ \ j -> do
189 writeM mnr (i :. j) (a ! ((ord ! i) :. j))
190 when (i < n - 1) $
191 writeM mnr (i :. j)
192 =<< min <$> readM mnr (i :. j) <*> readM mnr (i + 1 :. j)
193 when (j < m - 1) $
194 writeM mnr (i :. j)
195 =<< min <$> readM mnr (i :. j) <*> readM mnr (i :. j + 1)
196 mnl <- newMArray @P (Sz m) maxBound
197 mxr <- newMArray @P (Sz m) minBound
198 let goI i
199 | i < n - 1 = do
200 loopM_ 0 (< m) (+ 1) $ \j -> do
201 val <- min (a ! ((ord ! i) :. j)) <$> readM mnl j
202 writeM mnl j val
203 when (j > 0) $
204 writeM mnl j . min val =<< readM mnl (j - 1)
205 loopM_ (m - 1) (>= 0) (subtract 1) $ \j -> do
206 val <- max (a ! ((ord ! i) :. j)) <$> readM mxr j
207 writeM mxr j val
208 when (j < m - 1) $
209 writeM mxr j . max val =<< readM mxr (j + 1)
210 let goJ j
211 | j < m - 1 = do
212 mnlVal <- readM mnl j
213 mxlVal <- readM mxl (i + 1 :. j)
214 mxrVal <- readM mxr (j + 1)
215 mnrVal <- readM mnr ((i + 1) :. (j + 1))
216 if mnlVal > mxlVal && mxrVal < mnrVal
217 then pure $ Just (i, j)
218 else goJ (j + 1)
219 | otherwise = pure Nothing
220 goJ 0 >>= \case
221 Nothing -> goI (i + 1)
222 Just pair -> pure $ Just pair
223 | otherwise = pure Nothing
224 mAns <- goI 0
225 Control.Monad.forM mAns $ \ (ansFirst, ansSecond) -> do
226 resVec <- createArrayS_ @BL (Sz n) $ \res ->
227 iforM_ ord $ \i ordIx -> do
228 writeM res ordIx $! if i <= ansFirst then R else B
229 pure (ansSecond + 1, A.toList resVec)
230
QUESTION
Typescript: deep keyof of a nested object, with related type
Asked 2021-Dec-02 at 09:30I'm looking for a way to have all keys / values pair of a nested object.
(For the autocomplete of MongoDB dot notation key / value type)
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9
Here is what I want to achieve, to make it becomes:
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16
In this answer, I can get the key with Leaves<IPerson>
.
So it becomes 'name' | 'age' | 'contact.address' | 'contact.visitDate'
.
And in another answer from @jcalz, I can get the deep, related value type, with DeepIndex<IPerson, ...>
.
Is it possible to group them together, to become type like TPerson
?
When I start this question, I was thinking it could be as easy as something like [K in keyof T]: T[K];
, with some clever transformation. But I was wrong. Here is what I need:
So the interface
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22
becomes
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30
No need to check for valid number
, the nature of Array / Index Signature should allow any number of elements.
The interface
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33
becomes
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38
Tuple should be the one which cares about valid index numbers.
3. Readonlyreadonly
attributes should be removed from the final structure.
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43
becomes
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46
The use case is for MongoDB, the _id
, _created_date
cannot be modified after the data has been created. _id: never
is not working in this case, since it will block the creation of TPerson
.
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52
becomes
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60
It's sufficient just to bring the optional flags to transformed structure.
5. Intersection1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63
becomes
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68
The interface
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71
becomes
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74
not
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74type TPerson = {
75 age: Date;
76 "age.toDateString": () => string;
77 "age.toTimeString": () => string;
78 "age.toLocaleDateString": {
79 ...
80}
81
We can give a list of Types to be the end node.
Here is what I don't need:ANSWER
Answered 2021-Dec-02 at 09:30In order to achieve this goal we need to create permutation of all allowed paths. For example:
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74type TPerson = {
75 age: Date;
76 "age.toDateString": () => string;
77 "age.toTimeString": () => string;
78 "age.toLocaleDateString": {
79 ...
80}
81type Structure = {
82 user: {
83 name: string,
84 surname: string
85 }
86}
87
88type BlackMagic<T>= T
89
90// user.name | user.surname
91type Result=BlackMagic<Structure>
92
Problem becomes more interesting with arrays and empty tuples.
Tuple, the array with explicit length, should be managed in this way:
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74type TPerson = {
75 age: Date;
76 "age.toDateString": () => string;
77 "age.toTimeString": () => string;
78 "age.toLocaleDateString": {
79 ...
80}
81type Structure = {
82 user: {
83 name: string,
84 surname: string
85 }
86}
87
88type BlackMagic<T>= T
89
90// user.name | user.surname
91type Result=BlackMagic<Structure>
92type Structure = {
93 user: {
94 arr: [1, 2],
95 }
96}
97
98type BlackMagic<T> = T
99
100// "user.arr" | "user.arr.0" | "user.arr.1"
101type Result = BlackMagic<Structure>
102
Logic is straitforward. But how we can handle number[]
? There is no guarantee that index 1
exists.
I have decided to use user.arr.${number}
.
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;